Repository: nielsbasjes/logparser Branch: main Commit: 0e5ab16f6270 Files: 212 Total size: 2.0 MB Directory structure: gitextract_a39vjp3u/ ├── .editorconfig ├── .github/ │ ├── FUNDING.yml │ └── workflows/ │ └── build.yml ├── .gitignore ├── .pmd ├── .travis.yml__ ├── CHANGELOG.md ├── CNAME ├── GeoIP2-TestData/ │ ├── Dockerfile │ ├── README.md │ ├── rebuild.sh │ ├── source-data/ │ │ ├── GeoIP2-City-Test.json │ │ ├── GeoIP2-Country-Test.json │ │ ├── GeoIP2-ISP-Test.json │ │ └── GeoLite2-ASN-Test.json │ └── test-data/ │ ├── GeoIP2-City-Test.mmdb │ ├── GeoIP2-Country-Test.mmdb │ ├── GeoIP2-ISP-Test.mmdb │ ├── GeoLite2-ASN-Test.mmdb │ └── write-test-data.pl ├── LICENSE ├── README-Hive.md ├── README-Java.md ├── README-Pig.md ├── README-geoip.md ├── README.md ├── _config.yml ├── devtools/ │ ├── docker/ │ │ ├── Dockerfile │ │ ├── bashcolors.sh │ │ ├── build_env_checks.sh │ │ ├── configure-for-user.sh │ │ ├── env.sh │ │ └── prompt.sh │ ├── logformat.conf │ ├── pom.xml │ ├── release.sh │ └── src/ │ └── main/ │ └── resources/ │ └── checkstyle/ │ ├── checkstyle.xml │ └── suppressions.xml ├── docs/ │ ├── CNAME │ └── README.md ├── examples/ │ ├── apache-beam/ │ │ ├── .gitignore │ │ ├── pom.xml │ │ └── src/ │ │ └── test/ │ │ ├── avro/ │ │ │ └── Record.avdl │ │ ├── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── parse/ │ │ │ └── httpdlog/ │ │ │ └── beam/ │ │ │ ├── TestCase.java │ │ │ ├── avro/ │ │ │ │ ├── ExpectedClick.java │ │ │ │ ├── TestParserDoFnAvro.java │ │ │ │ └── TestParserDoFnAvroInline.java │ │ │ └── pojo/ │ │ │ ├── MyRecord.java │ │ │ ├── TestParserDoFnClass.java │ │ │ └── TestParserDoFnInline.java │ │ └── resources/ │ │ └── log4j.properties │ ├── apache-flink/ │ │ ├── .gitignore │ │ ├── pom.xml │ │ └── src/ │ │ └── test/ │ │ ├── avro/ │ │ │ └── Record.avdl │ │ ├── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── parse/ │ │ │ └── httpdlog/ │ │ │ └── flink/ │ │ │ ├── TestCase.java │ │ │ ├── avro/ │ │ │ │ ├── ExpectedClick.java │ │ │ │ ├── TestParserMapFunctionAvroClass.java │ │ │ │ └── TestParserMapFunctionAvroInline.java │ │ │ └── pojo/ │ │ │ ├── MyRecord.java │ │ │ ├── TestParserMapFunctionClass.java │ │ │ └── TestParserMapFunctionInline.java │ │ └── resources/ │ │ └── log4j.properties │ ├── apache-hadoop-mapreduce/ │ │ ├── .gitignore │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── assembly/ │ │ │ └── job.xml │ │ └── java/ │ │ └── nl/ │ │ └── basjes/ │ │ └── hadoop/ │ │ └── io/ │ │ └── input/ │ │ └── Wordcount.java │ ├── demolog/ │ │ ├── README.md │ │ └── hackers-access.log │ ├── java-pojo/ │ │ ├── pom.xml │ │ └── src/ │ │ └── main/ │ │ ├── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── parse/ │ │ │ ├── Main.java │ │ │ └── MyRecord.java │ │ └── resources/ │ │ └── log4j.properties │ └── pom.xml ├── httpdlog/ │ ├── httpdlog-inputformat/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── assembly/ │ │ │ │ └── job.xml │ │ │ └── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── hadoop/ │ │ │ └── input/ │ │ │ ├── ApacheHttpdLogfileInputFormat.java │ │ │ ├── ApacheHttpdLogfileRecordReader.java │ │ │ └── ParsedRecord.java │ │ └── test/ │ │ ├── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── hadoop/ │ │ │ └── input/ │ │ │ ├── TestApacheHttpdLogfileInputFormat.java │ │ │ ├── TestGetAllFields.java │ │ │ └── TestParsedRecord.java │ │ └── resources/ │ │ ├── access.log │ │ └── log4j.properties │ ├── httpdlog-parser/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── antlr4/ │ │ │ │ └── nl/ │ │ │ │ └── basjes/ │ │ │ │ └── parse/ │ │ │ │ └── strftime/ │ │ │ │ └── StrfTime.g4 │ │ │ ├── assembly/ │ │ │ │ └── job.xml │ │ │ ├── java/ │ │ │ │ └── nl/ │ │ │ │ └── basjes/ │ │ │ │ └── parse/ │ │ │ │ └── httpdlog/ │ │ │ │ ├── ApacheHttpdLogFormatDissector.java │ │ │ │ ├── HttpdLogFormatDissector.java │ │ │ │ ├── HttpdLoglineParser.java │ │ │ │ ├── NginxHttpdLogFormatDissector.java │ │ │ │ ├── Utils.java │ │ │ │ └── dissectors/ │ │ │ │ ├── HttpFirstLineDissector.java │ │ │ │ ├── HttpFirstLineProtocolDissector.java │ │ │ │ ├── HttpUriDissector.java │ │ │ │ ├── ModUniqueIdDissector.java │ │ │ │ ├── QueryStringFieldDissector.java │ │ │ │ ├── RequestCookieListDissector.java │ │ │ │ ├── ResponseSetCookieDissector.java │ │ │ │ ├── ResponseSetCookieListDissector.java │ │ │ │ ├── ScreenResolutionDissector.java │ │ │ │ ├── StrfTimeStampDissector.java │ │ │ │ ├── StrfTimeToDateTimeFormatter.java │ │ │ │ ├── TimeStampDissector.java │ │ │ │ ├── geoip/ │ │ │ │ │ ├── AbstractGeoIPDissector.java │ │ │ │ │ ├── GeoIPASNDissector.java │ │ │ │ │ ├── GeoIPCityDissector.java │ │ │ │ │ ├── GeoIPCountryDissector.java │ │ │ │ │ └── GeoIPISPDissector.java │ │ │ │ ├── nginxmodules/ │ │ │ │ │ ├── CoreLogModule.java │ │ │ │ │ ├── GeoIPModule.java │ │ │ │ │ ├── KubernetesIngressModule.java │ │ │ │ │ ├── NginxModule.java │ │ │ │ │ ├── SslModule.java │ │ │ │ │ ├── UpstreamListDissector.java │ │ │ │ │ ├── UpstreamModule.java │ │ │ │ │ └── VariousModule.java │ │ │ │ ├── tokenformat/ │ │ │ │ │ ├── NamedTokenParser.java │ │ │ │ │ ├── ParameterizedTokenParser.java │ │ │ │ │ ├── Token.java │ │ │ │ │ ├── TokenFormatDissector.java │ │ │ │ │ ├── TokenOutputField.java │ │ │ │ │ ├── TokenParser.java │ │ │ │ │ └── TokenSorterByStartPos.java │ │ │ │ └── translate/ │ │ │ │ ├── ConvertCLFIntoNumber.java │ │ │ │ ├── ConvertMillisecondsIntoMicroseconds.java │ │ │ │ ├── ConvertNumberIntoCLF.java │ │ │ │ ├── ConvertSecondsWithMillisStringDissector.java │ │ │ │ └── TypeConvertBaseDissector.java │ │ │ └── resources/ │ │ │ └── version/ │ │ │ └── Version.java.template │ │ └── test/ │ │ ├── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── parse/ │ │ │ └── httpdlog/ │ │ │ ├── ApacheHttpdAllFieldsTest.java │ │ │ ├── ApacheHttpdLogParserTest.java │ │ │ ├── BasicOverallTest.java │ │ │ ├── ClientHintsTest.java │ │ │ ├── CookiesTest.java │ │ │ ├── EdgeCasesTest.java │ │ │ ├── JettyLogFormatParserTest.java │ │ │ ├── JsonLogFormatTest.java │ │ │ ├── MultiLineHttpdLogParserTest.java │ │ │ ├── NginxLogFormatJsonTest.java │ │ │ ├── NginxLogFormatTest.java │ │ │ ├── UtilsTest.java │ │ │ ├── dissectors/ │ │ │ │ ├── TestCookieDissector.java │ │ │ │ ├── TestGeoIPDissectors.java │ │ │ │ ├── TestHttpFirstLineDissector.java │ │ │ │ ├── TestHttpUriDissector.java │ │ │ │ ├── TestModUniqueIdDissector.java │ │ │ │ ├── TestQueryStringDissector.java │ │ │ │ └── TestTimeStampDissector.java │ │ │ ├── nginxmodules/ │ │ │ │ ├── NginxAllFieldsTest.java │ │ │ │ └── NginxUpstreamTest.java │ │ │ └── translate/ │ │ │ └── TestTranslators.java │ │ └── resources/ │ │ └── log4j.properties │ ├── httpdlog-serde/ │ │ ├── pom.xml │ │ └── src/ │ │ ├── main/ │ │ │ ├── assembly/ │ │ │ │ └── udf.xml │ │ │ └── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── parse/ │ │ │ └── httpdlog/ │ │ │ └── ApacheHttpdlogDeserializer.java │ │ └── test/ │ │ ├── java/ │ │ │ └── nl/ │ │ │ └── basjes/ │ │ │ └── parse/ │ │ │ └── httpdlog/ │ │ │ ├── TestAllDissectorTypes.java │ │ │ └── TestApacheHttpdlogDeserializer.java │ │ └── resources/ │ │ └── log4j.properties │ └── pom.xml ├── parser-core/ │ ├── pom.xml │ └── src/ │ ├── main/ │ │ ├── assembly/ │ │ │ └── job.xml │ │ └── java/ │ │ └── nl/ │ │ └── basjes/ │ │ └── parse/ │ │ └── core/ │ │ ├── Casts.java │ │ ├── Dissector.java │ │ ├── Field.java │ │ ├── Parsable.java │ │ ├── ParsedField.java │ │ ├── Parser.java │ │ ├── SimpleDissector.java │ │ ├── Value.java │ │ └── exceptions/ │ │ ├── DissectionFailure.java │ │ ├── FatalErrorDuringCallOfSetterMethod.java │ │ ├── InvalidDissectorException.java │ │ ├── InvalidFieldMethodSignature.java │ │ └── MissingDissectorsException.java │ └── test/ │ ├── java/ │ │ └── nl/ │ │ └── basjes/ │ │ └── parse/ │ │ └── core/ │ │ ├── ParserCastsTest.java │ │ ├── ParserDissectionOutputTypesTest.java │ │ ├── ParserDuplicateOutputTest.java │ │ ├── ParserExceptionsTest.java │ │ ├── ParserInfiniteLoopTest.java │ │ ├── ParserNormalTest.java │ │ ├── ParserNormalTestRecord.java │ │ ├── ParserResetTest.java │ │ ├── ParserTypeColissionTest.java │ │ ├── ParserTypeRemappingEdgeCase.java │ │ ├── TestBadAPIUsage.java │ │ ├── annotation/ │ │ │ ├── TestFieldSetters.java │ │ │ ├── TestFieldSettersAlwaysCombined.java │ │ │ ├── TestFieldSettersAlwaysSeparate.java │ │ │ ├── TestFieldSettersNotEmpty.java │ │ │ └── TestFieldSettersNotNull.java │ │ ├── convert/ │ │ │ └── ValueConvertTest.java │ │ ├── reference/ │ │ │ ├── BarDissector.java │ │ │ ├── FooDissector.java │ │ │ ├── FooSpecialDissector.java │ │ │ ├── ReferenceTest.java │ │ │ └── ReferenceTestDouble.java │ │ └── test/ │ │ ├── DissectorTester.java │ │ ├── EmptyValuesDissector.java │ │ ├── MyDissectorTester.java │ │ ├── NormalValuesDissector.java │ │ ├── NullValuesDissector.java │ │ ├── TestRecord.java │ │ ├── TestUltimateDummyDissector.java │ │ ├── TestUltimateDummyDissectorFailurelogging.java │ │ └── UltimateDummyDissector.java │ └── resources/ │ └── log4j.properties ├── pom.xml ├── renovate.json ├── start-docker.sh └── utils/ ├── PojoGenerator/ │ ├── pom.xml │ └── src/ │ └── main/ │ └── java/ │ └── nl/ │ └── basjes/ │ └── parse/ │ └── httpdlog/ │ └── PojoGenerator.java └── pom.xml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # root = true [*] charset = utf-8 end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true indent_style = space [*.java] indent_size = 4 [*.xml] indent_size = 2 # Tab indentation (no size specified) ================================================ FILE: .github/FUNDING.yml ================================================ github: nielsbasjes custom: https://www.paypal.me/nielsbasjes ================================================ FILE: .github/workflows/build.yml ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # name: Logparser on: push: branches: [ main ] pull_request: branches: [ main ] jobs: build: name: Build with Java ${{ matrix.java }} runs-on: ubuntu-latest steps: - name: Checkout sourcecode uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Cache Local Maven Repository uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} restore-keys: | ${{ runner.os }}-maven- - name: 'Setup: Install JDK 21, 25' uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: 'temurin' java-version: | 21 25 - name: Build Logparser run: mvn -B clean package - name: Codecov uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2 # v6.0.0 with: token: ${{ secrets.CODECOV_TOKEN }} ================================================ FILE: .gitignore ================================================ *.class # Maven dependency-reduced-pom.xml # Package Files # *.jar *.war *.ear target *.bak *.swp *~ bin __* #Eclipse stuff .metadata .settings .classpath .project hs_err_pid*.log #IntelliJ stuff .idea *.iml #test files x xx y yy z zz #Hive/Hadoop logs SecurityAuth-*.audit hadoop*.log *-audit.log rm-appsummary.log # Docker devtools/docker/_m2/ devtools/docker/_gnupg/ ================================================ FILE: .pmd ================================================ false .ruleset AvoidDecimalLiteralsInBigDecimalConstructor Basic Rules AvoidMultipleUnaryOperators Basic Rules AvoidThreadGroup Basic Rules AvoidUsingHardCodedIP Basic Rules AvoidUsingOctalValues Basic Rules BigIntegerInstantiation Basic Rules BooleanInstantiation Basic Rules BrokenNullCheck Basic Rules CheckResultSet Basic Rules ClassCastExceptionWithToArray Basic Rules CollapsibleIfStatements Basic Rules DoubleCheckedLocking Basic Rules EmptyCatchBlock Basic Rules EmptyFinallyBlock Basic Rules EmptyIfStmt Basic Rules EmptyInitializer Basic Rules EmptyStatementNotInLoop Basic Rules EmptyStaticInitializer Basic Rules EmptySwitchStatements Basic Rules EmptySynchronizedBlock Basic Rules EmptyTryBlock Basic Rules EmptyWhileStmt Basic Rules ForLoopShouldBeWhileLoop Basic Rules JumbledIncrementer Basic Rules MisplacedNullCheck Basic Rules OverrideBothEqualsAndHashcode Basic Rules ReturnFromFinallyBlock Basic Rules UnconditionalIfStatement Basic Rules UnnecessaryConversionTemporary Basic Rules UnnecessaryFinalModifier Basic Rules UnnecessaryReturn Basic Rules UnusedNullCheckInEquals Basic Rules UselessOperationOnImmutable Basic Rules UselessOverridingMethod Basic Rules ForLoopsMustUseBraces Braces Rules IfElseStmtsMustUseBraces Braces Rules IfStmtsMustUseBraces Braces Rules WhileLoopsMustUseBraces Braces Rules CloneThrowsCloneNotSupportedException Clone Implementation Rules ProperCloneImplementation Clone Implementation Rules CyclomaticComplexity Code Size Rules ExcessiveClassLength Code Size Rules ExcessiveMethodLength Code Size Rules ExcessiveParameterList Code Size Rules ExcessivePublicCount Code Size Rules NcssConstructorCount Code Size Rules NcssMethodCount Code Size Rules NcssTypeCount Code Size Rules NPathComplexity Code Size Rules TooManyFields Code Size Rules TooManyMethods Code Size Rules AssignmentInOperand Controversial Rules AtLeastOneConstructor Controversial Rules AvoidAccessibilityAlteration Controversial Rules AvoidUsingNativeCode Controversial Rules AvoidUsingShortType Controversial Rules AvoidUsingVolatile Controversial Rules BooleanInversion Controversial Rules CallSuperInConstructor Controversial Rules DefaultPackage Controversial Rules DoNotCallGarbageCollectionExplicitly Controversial Rules DontImportSun Controversial Rules SuspiciousOctalEscape Controversial Rules UnnecessaryConstructor Controversial Rules UnnecessaryParentheses Controversial Rules UnusedModifier Controversial Rules CouplingBetweenObjects Coupling Rules ExcessiveImports Coupling Rules AbstractClassWithoutAbstractMethod Design Rules AbstractClassWithoutAnyMethod Design Rules AccessorClassGeneration Design Rules AssignmentToNonFinalStatic Design Rules AvoidConstantsInterface Design Rules AvoidDeeplyNestedIfStmts Design Rules AvoidInstanceofChecksInCatchClause Design Rules AvoidProtectedFieldInFinalClass Design Rules AvoidReassigningParameters Design Rules AvoidSynchronizedAtMethodLevel Design Rules BadComparison Design Rules ClassWithOnlyPrivateConstructorsShouldBeFinal Design Rules CloseResource Design Rules CompareObjectsWithEquals Design Rules ConfusingTernary Design Rules ConstructorCallsOverridableMethod Design Rules DefaultLabelNotLastInSwitchStmt Design Rules EmptyMethodInAbstractClassShouldBeAbstract Design Rules EqualsNull Design Rules FinalFieldCouldBeStatic Design Rules IdempotentOperations Design Rules ImmutableField Design Rules InstantiationToGetClass Design Rules MissingBreakInSwitch Design Rules MissingStaticMethodInNonInstantiatableClass Design Rules NonCaseLabelInSwitchStatement Design Rules NonStaticInitializer Design Rules NonThreadSafeSingleton Design Rules OptimizableToArrayCall Design Rules PositionLiteralsFirstInComparisons Design Rules PreserveStackTrace Design Rules ReturnEmptyArrayRatherThanNull Design Rules SimpleDateFormatNeedsLocale Design Rules SimplifyBooleanExpressions Design Rules SimplifyBooleanReturns Design Rules SimplifyConditional Design Rules SingularField Design Rules SwitchDensity Design Rules SwitchStmtsShouldHaveDefault Design Rules TooFewBranchesForASwitchStatement Design Rules UncommentedEmptyConstructor Design Rules UncommentedEmptyMethod Design Rules UnnecessaryLocalBeforeReturn Design Rules UnsynchronizedStaticDateFormatter Design Rules UseCollectionIsEmpty Design Rules UseLocaleWithCaseConversions Design Rules UseNotifyAllInsteadOfNotify Design Rules UseSingleton Design Rules AvoidCallingFinalize Finalizer Rules EmptyFinalizer Finalizer Rules FinalizeDoesNotCallSuperFinalize Finalizer Rules FinalizeOnlyCallsSuperFinalize Finalizer Rules FinalizeOverloaded Finalizer Rules FinalizeShouldBeProtected Finalizer Rules DontImportJavaLang Import Statement Rules DuplicateImports Import Statement Rules ImportFromSamePackage Import Statement Rules TooManyStaticImports Import Statement Rules DoNotCallSystemExit J2EE Rules DoNotUseThreads J2EE Rules LocalHomeNamingConvention J2EE Rules LocalInterfaceSessionNamingConvention J2EE Rules MDBAndSessionBeanNamingConvention J2EE Rules RemoteInterfaceNamingConvention J2EE Rules RemoteSessionInterfaceNamingConvention J2EE Rules StaticEJBFieldShouldBeFinal J2EE Rules UseProperClassLoader J2EE Rules ProperLogger Jakarta Commons Logging Rules UseCorrectExceptionLogging Jakarta Commons Logging Rules AvoidPrintStackTrace Java Logging Rules LoggerIsNotStaticFinal Java Logging Rules MoreThanOneLogger Java Logging Rules SystemPrintln Java Logging Rules MissingSerialVersionUID JavaBean Rules JUnitAssertionsShouldIncludeMessage JUnit Rules JUnitSpelling JUnit Rules JUnitStaticSuite JUnit Rules JUnitTestsShouldIncludeAssert JUnit Rules SimplifyBooleanAssertion JUnit Rules TestClassWithoutTestCases JUnit Rules UnnecessaryBooleanAssertion JUnit Rules UseAssertEqualsInsteadOfAssertTrue JUnit Rules UseAssertNullInsteadOfAssertTrue JUnit Rules UseAssertSameInsteadOfAssertTrue JUnit Rules AvoidAssertAsIdentifier Migration Rules AvoidEnumAsIdentifier Migration Rules ByteInstantiation Migration Rules IntegerInstantiation Migration Rules JUnit4SuitesShouldUseSuiteAnnotation Migration Rules JUnit4TestShouldUseAfterAnnotation Migration Rules JUnit4TestShouldUseBeforeAnnotation Migration Rules JUnit4TestShouldUseTestAnnotation Migration Rules JUnitUseExpected Migration Rules LongInstantiation Migration Rules ReplaceEnumerationWithIterator Migration Rules ReplaceHashtableWithMap Migration Rules ReplaceVectorWithList Migration Rules ShortInstantiation Migration Rules AbstractNaming Naming Rules AvoidDollarSigns Naming Rules AvoidFieldNameMatchingMethodName Naming Rules AvoidFieldNameMatchingTypeName Naming Rules BooleanGetMethodName Naming Rules ClassNamingConventions Naming Rules LongVariable Naming Rules MethodNamingConventions Naming Rules MethodWithSameNameAsEnclosingClass Naming Rules MisleadingVariableName Naming Rules NoPackage Naming Rules PackageCase Naming Rules ShortMethodName Naming Rules ShortVariable Naming Rules SuspiciousConstantFieldName Naming Rules SuspiciousEqualsMethodName Naming Rules SuspiciousHashcodeMethodName Naming Rules VariableNamingConventions Naming Rules AddEmptyString Optimization Rules AvoidArrayLoops Optimization Rules AvoidInstantiatingObjectsInLoops Optimization Rules MethodArgumentCouldBeFinal Optimization Rules SimplifyStartsWith Optimization Rules UnnecessaryWrapperObjectCreation Optimization Rules UseArrayListInsteadOfVector Optimization Rules UseArraysAsList Optimization Rules UseStringBufferForStringAppends Optimization Rules ArrayIsStoredDirectly Security Code Guidelines MethodReturnsInternalArray Security Code Guidelines AvoidCatchingNPE Strict Exception Rules AvoidCatchingThrowable Strict Exception Rules AvoidRethrowingException Strict Exception Rules AvoidThrowingNewInstanceOfSameException Strict Exception Rules AvoidThrowingNullPointerException Strict Exception Rules AvoidThrowingRawExceptionTypes Strict Exception Rules DoNotExtendJavaLangError Strict Exception Rules DoNotThrowExceptionInFinally Strict Exception Rules ExceptionAsFlowControl Strict Exception Rules AppendCharacterWithChar String and StringBuffer Rules AvoidDuplicateLiterals String and StringBuffer Rules AvoidStringBufferField String and StringBuffer Rules ConsecutiveLiteralAppends String and StringBuffer Rules InefficientEmptyStringCheck String and StringBuffer Rules InefficientStringBuffering String and StringBuffer Rules InsufficientStringBufferDeclaration String and StringBuffer Rules StringBufferInstantiationWithChar String and StringBuffer Rules StringInstantiation String and StringBuffer Rules StringToString String and StringBuffer Rules UnnecessaryCaseChange String and StringBuffer Rules UseEqualsToCompareStrings String and StringBuffer Rules UseIndexOfChar String and StringBuffer Rules UselessStringValueOf String and StringBuffer Rules UseStringBufferLength String and StringBuffer Rules CloneMethodMustImplementCloneable Type Resolution Rules LooseCoupling Type Resolution Rules SignatureDeclareThrowsException Type Resolution Rules UnusedImports Type Resolution Rules UnusedFormalParameter Unused Code Rules UnusedLocalVariable Unused Code Rules UnusedPrivateField Unused Code Rules UnusedPrivateMethod Unused Code Rules false true ================================================ FILE: .travis.yml__ ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # language: java dist: trusty jdk: - oraclejdk8 after_success: - mvn -PEnableReportPlugins coveralls:report cache: directories: - '$HOME/.m2/repository' ================================================ FILE: CHANGELOG.md ================================================ This is intended as an overview of the major changes v6.0.1-SNAPSHOT === - ... v6.0.0 === - Updated to need Java 21! - Update Serde to Hive 4.2.0 - Updated Flink and Beam examples to latest versions - GeoIP update no longer supports the "metrocode" v5.11.0 === - Update Serde to Hive 4.0.0 v5.10.0 === - Do not fail on logline specific parse errors, simply not provide the expected dissections. v5.9.0 === - Print the parsed values of a wildcard in DissectorTester::printAllPossibleValues - Allow bad requests to be parsed anyway. - Drop Apache Pig support (this tool is no longer used by anyone) v5.8 === - getPossiblePaths sorts the list by fieldname. - Removed GeoIP fields averageincome and populationdensity which are not part of any real mmdb file. - Dropped the already disabled Storm example - Fully switched to Junit 5 - Require JDK 11 or newer to build - Workaround for change in Unicode CLDR(and thus Java 17): they changed the short name of "September" in Locale.UK to "Sept" which causes parse errors. - Fixed bug regarding escaped characters in headers. v5.7 === - Updated dependencies - When adding a type remapping with an explicit cast this cast was lost and replaced by "STRING_ONLY". v5.6 === - Fix bug that in some cases values would be reported multiple times. v5.5 === - Handle HTML encoded values in the URL better v5.4 === - Updated many dependencies - Fixed extracting the timezone - In url parsing missing values are now 'absent' (i.e. not set) - Handle loglines when the upstream module is not running (i.e. fields are a '-') v5.3 === - Updated many dependencies v5.2 === - Improve regex performance - Added basic support for the NGinx Upstream, SSL, GeoIP and all other documented modules - Added basic support for parsing the Kubernetes Ingress logformat variables - Disallow some Dissector methods to return a null. - Updated many dependencies: Hadoop, Flink, Beam etc. v5.1 === - Parse epoch seconds `%{%s}t` - Added GeoIP2 dissectors for City, Country and ASN data. - Improved output of dissector testing framework. v5.0 === - The %u specifier allowed a space which broke parsing if the field after it also allowed space. - If a custom time format does not contain a timezone we assume a default timezone (UTC). - Fix extracting milliseconds, added extracting microseconds and nanoseconds. - Allow `%{%usec_frac}t` in addition to `%{usec_frac}t` (same msec_frac). - Introduce a setterPolicy to determine if the setter is called in case of a NULL or EMPTY value. - Replace Cobertura with Jacoco because of Java 8 - Remove Yauaa from tests and examples because of circular dependency between the projects. - Make Java API more fluent (breaks backwards compatibility with external dissectors). v4.0 === - Switching to require Java 8 - Parser instance is now serializable. - Added example on using with Apache Flink - Added example on using with Apache Beam - Rewrote Apache Storm code and move to examples - Many changes in Exception handling v3.1 === - Handle illegal data: Double # in the URL - Handle illegal data: Firstline is rubbish (Reported by Yong Zhang - java8964). v3.0 === - Accept the NGinx logformat. - Output the httpd parser git info, build timestamp and version info on startup. - Fixed problem when using a different root dissector than provided by default. - Created a testing toolkit for dissectors and improved several tests. - Allow a dissector to add an additional dissector (needed for custom time format parsing) - Support for parsing many (not all) of the possible custom time format fields. - Allow changing the parser even after first use (makes it more flexible to use). - Allow a dissector to return an empty 'extra part' to allow an alternate form of type remapping - Improved test coverage - Dissection the setcookies expire value was not deterministic and an absent 'expire' value is now returned as null instead of the 'now' timestamp. - Implemented `%{UNIT}T` - Implemented converters between several closely related formats (BYTES/BYTESCLF, time related formats) - Token based parsers can output multiple values for the same parameter. - Implemented all < and > directives for Apache logformat - Implemented `%{VARNAME}^ti` and `%{VARNAME}^to` **RELEVANT CHANGES COMPARED WITH THE 2.X VERSION**: These fields are now reported as deprecated. - `%b` changed from "BYTES:response.body.bytesclf" to "BYTESCLF:response.body.bytes" - `%D` changed from "server.process.time" to "response.server.processing.time" - `%{msec_frac}t` changed from "request.receive.time.begin.msec_frac" to "request.receive.time.msec_frac" - `%{usec_frac}t` changed from "request.receive.time.begin.usec_frac" to "request.receive.time.usec_frac" - `%{msec}t` changed from "request.receive.time.begin.msec" to "request.receive.time.msec" - `%{usec}t` changed from "request.receive.time.begin.usec" to "request.receive.time.usec" v2.8 === - Allow parsing mixed case timeformats - Added the ISO 8601 'date' output for parsed times (Is string "yyyy-MM-dd") - Added the ISO 8601 'time' output for parsed times (Is string "HH:mm:ss" ) - Solve parse error when a HTTP method like "VERSION-CONTROL" is used. - Fixed NPE in specific combination of cast and setter type and a null value - Improved test coverage v2.7 === - Handle the effects of mod_reqtimeout giving a http 408 (reported by Diogo Sant'Ana) - Added option to optionally continue even when some requested dissectors are missing (Java only). v2.6 === - Buildin fix for the problems in Jetty logging v2.5 === - Simply treat the `%{...}t` as a text field you can retrieve (instead of failing if it occurs). - Change URI dissector to allow URIs like android-app://... - Change URI dissector to allow % in the URI when it is not an escape sequence (like in `?promo=Give-5%-discount`) v2.4 === - Rewrote the way parsed values are passed around. Improves accuracy and performance in specific cases. - Now support parsing the first line even if it is chopped by Apache httpd because of an URI longer than 8000 bytes. - Fixed an infinite recursion problem. - Fixed Timestamp unit test (test was broken, code was fine). v2.3 === - The raw timestamp extracted from the Apache logfiles no longer contains the surrounding '[' ']'. v2.2 === - Accept multiple logformat lines as a single 'multiline' input string. v2.1.1 === - Fixed simple problem in the PIG example output v2.1 === - Dissect the unique ID from mod_unique_id. - [PIG] Make getting the example code for PIG a bit easier v2.0 === - Fixed reading logfiles from before 2000 - Rearranged the Java packages to make the structure more logical. - Changed license from GPL to Apache v2.0 v1.9.1 === - Allow urls that have a space (which is incorrect but does happen). v1.9 === - [PIG] Support for getting a map[] of values (useful for cookies and query string parameters) - [PIG] Output the possible values as a complete working Pig statement. Older === Just see the commit logs Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: CNAME ================================================ logparser.basjes.nl ================================================ FILE: GeoIP2-TestData/Dockerfile ================================================ # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. FROM perl:5.40.0-buster RUN cpan File::Slurper RUN cpan Cpanel::JSON::XS RUN cpan Math::Int128 RUN cpan MaxMind::DB::Writer::Serializer WORKDIR "/GeoIPTestData/test-data" CMD ["/GeoIPTestData/test-data/write-test-data.pl"] ================================================ FILE: GeoIP2-TestData/README.md ================================================ I copied some of the files from https://github.com/maxmind/MaxMind-DB/ and modified them to suit my own needs. These base files are only used for unit tests in this project and are licensed as This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA. ================================================ FILE: GeoIP2-TestData/rebuild.sh ================================================ #!/bin/bash # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" cd "${DIR}" || exit 1 PROJECTNAME=GeoIPTestData IMAGE_NAME=geo-ip-testdatabuilder CONTAINER_NAME=GeoIPTestDataBuilder docker build -t "${IMAGE_NAME}" . if [ "$(uname -s)" == "Linux" ]; then USER_NAME=${SUDO_USER:=${USER}} USER_ID=$(id -u "${USER_NAME}") GROUP_ID=$(id -g "${USER_NAME}") else # boot2docker uid and gid USER_NAME=${USER} USER_ID=1000 GROUP_ID=50 fi # man docker-run # When using SELinux, mounted directories may not be accessible # to the container. To work around this, with Docker prior to 1.7 # one needs to run the "chcon -Rt svirt_sandbox_file_t" command on # the directories. With Docker 1.7 and later the z mount option # does this automatically. # Since Docker 1.7 was release 5 years ago we only support 1.7 and newer. V_OPTS=:z COMMAND=( "$@" ) if [ $# -eq 0 ]; then # COMMAND=( "bash" "-i" ) COMMAND=( ) fi ( cd "${DIR}/test-data" && rm *.mmdb ) docker run --rm=true -i -t \ -u "${USER_ID}" \ -v "${PWD}:/GeoIPTestData${V_OPTS:-}" \ -w "/GeoIPTestData/test-data" \ --name "${CONTAINER_NAME}" \ "${IMAGE_NAME}" \ "${COMMAND[@]}" ================================================ FILE: GeoIP2-TestData/source-data/GeoIP2-City-Test.json ================================================ [ { "::80.100.47.45/118": { "city": { "confidence": 1, "geoname_id": "1234", "names": { "en": "Amstelveen" } }, "postal": { "code": "1187", "confidence": 2 }, "subdivisions": [ { "confidence": 3, "geoname_id": 2345, "iso_code": "NH", "names": { "en": "Noord Holland" } } ], "continent": { "code": "EU", "geoname_id": 6255148, "names": { "de": "Europa", "en": "Europe", "es": "Europa", "fr": "Europe", "ja": "ヨーロッパ", "pt-BR": "Europa", "ru": "Европа", "zh-CN": "欧洲" } }, "country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "confidence": 42, "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } }, "location": { "accuracy_radius": 4, "latitude": "52.5", "longitude": "5.75", "time_zone": "Europe/Amsterdam", "metro_code" : "5" }, "registered_country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } } } }, { "2001:980:91c0::/56": { "city": { "confidence": 11, "geoname_id": "1234", "names": { "en": "Amstelveen" } }, "postal": { "code": "1187", "confidence": 12 }, "subdivisions": [ { "confidence": 13, "geoname_id": 2345, "iso_code": "NH", "names": { "en": "Noord Holland" } } ], "continent": { "code": "EU", "geoname_id": 6255148, "names": { "de": "Europa", "en": "Europe", "es": "Europa", "fr": "Europe", "ja": "ヨーロッパ", "pt-BR": "Europa", "ru": "Европа", "zh-CN": "欧洲" } }, "country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "confidence": 42, "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } }, "location": { "accuracy_radius": 14, "latitude": "52.5", "longitude": "5.75", "time_zone": "Europe/Amsterdam", "metro_code": "15" }, "registered_country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } } } } ] ================================================ FILE: GeoIP2-TestData/source-data/GeoIP2-Country-Test.json ================================================ [ { "::80.100.47.45/118": { "continent": { "code": "EU", "geoname_id": 6255148, "names": { "de": "Europa", "en": "Europe", "es": "Europa", "fr": "Europe", "ja": "ヨーロッパ", "pt-BR": "Europa", "ru": "Европа", "zh-CN": "欧洲" } }, "country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "confidence": 42, "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } }, "registered_country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } } } }, { "2001:980:91c0::/56": { "continent": { "code": "EU", "geoname_id": 6255148, "names": { "de": "Europa", "en": "Europe", "es": "Europa", "fr": "Europe", "ja": "ヨーロッパ", "pt-BR": "Europa", "ru": "Европа", "zh-CN": "欧洲" } }, "country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "confidence": 42, "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } }, "registered_country": { "geoname_id": 2750405, "is_in_european_union": true, "iso_code": "NL", "names": { "de": "Niederlande", "en": "Netherlands", "es": "Holanda", "fr": "Pays-Bas", "ja": "オランダ王国", "pt-BR": "Países Baixos", "ru": "Нидерланды", "zh-CN": "荷兰" } } } } ] ================================================ FILE: GeoIP2-TestData/source-data/GeoIP2-ISP-Test.json ================================================ [ { "::80.100.47.45/118": { "autonomous_system_number": 4444, "autonomous_system_organization": "Basjes Global Network", "isp": "Basjes ISP", "organization": "Niels Basjes" } }, { "2001:980:91c0::/56": { "autonomous_system_number": 6666, "autonomous_system_organization": "Basjes Global Network IPv6", "isp": "Basjes ISP IPv6", "organization": "Niels Basjes IPv6" } } ] ================================================ FILE: GeoIP2-TestData/source-data/GeoLite2-ASN-Test.json ================================================ [ { "::80.100.47.45/118": { "autonomous_system_number": 4444, "autonomous_system_organization": "Basjes Global Network" } }, { "2001:980:91c0::/56": { "autonomous_system_number": 6666, "autonomous_system_organization": "Basjes Global Network IPv6" } } ] ================================================ FILE: GeoIP2-TestData/test-data/write-test-data.pl ================================================ #!/usr/bin/env perl use strict; use warnings; use autodie; use utf8; use Cwd qw( abs_path ); use File::Basename qw( dirname ); use File::Slurper qw( read_binary write_binary ); use Cpanel::JSON::XS 4.16 qw( decode_json ); use Math::Int128 qw( MAX_UINT128 string_to_uint128 uint128 ); use MaxMind::DB::Writer::Serializer 0.100004; use MaxMind::DB::Writer::Tree 0.100004; use MaxMind::DB::Writer::Util qw( key_for_data ); use Net::Works::Network (); use Test::MaxMind::DB::Common::Util qw( standard_test_metadata ); my $Dir = dirname( abs_path($0) ); sub main { # my @sizes = ( 24, 28, 32 ); # my @ipv4_range = ( '1.1.1.1', '1.1.1.32' ); # my @ipv4_subnets = Net::Works::Network->range_as_subnets(@ipv4_range); # for my $record_size (@sizes) { # write_test_db( # $record_size, # \@ipv4_subnets, # { ip_version => 4 }, # 'ipv4', # ); # } # write_broken_pointers_test_db( # 24, # \@ipv4_subnets, # { ip_version => 4 }, # 'broken-pointers', # ); # write_broken_search_tree_db( # 24, # \@ipv4_subnets, # { ip_version => 4 }, # 'broken-search-tree', # ); # my @ipv6_subnets = Net::Works::Network->range_as_subnets( # '::1:ffff:ffff', # '::2:0000:0059' # ); # for my $record_size (@sizes) { # write_test_db( # $record_size, # \@ipv6_subnets, # { ip_version => 6 }, # 'ipv6', # ); # # write_test_db( # $record_size, # [ # @ipv6_subnets, # Net::Works::Network->range_as_subnets( @ipv4_range, 6 ), # ], # { ip_version => 6 }, # 'mixed', # ); # } # write_decoder_test_db(); # write_pointer_decoder_test_db(); # write_deeply_nested_structures_db(); write_geoip2_dbs(); # write_broken_geoip2_city_db(); # write_invalid_node_count(); # write_no_ipv4_tree_db(); # write_no_map_db( \@ipv4_subnets ); # write_test_serialization_data(); # write_db_with_metadata_pointers(); } # sub write_broken_pointers_test_db { # no warnings 'redefine'; # # my $orig_store_data = MaxMind::DB::Writer::Serializer->can('store_data'); # # # This breaks the value of the record for the 1.1.1.32 network, causing it # # to point outside the database. # local *MaxMind::DB::Writer::Serializer::store_data = sub { # my $data_pointer = shift->$orig_store_data(@_); # my $value = $_[1]; # if ( ref($value) eq 'HASH' # && exists $value->{ip} # && $value->{ip} eq '1.1.1.32' ) { # # $data_pointer += 100_000; # } # return $data_pointer; # }; # # # The next hack will poison the data section for the 1.1.16/28 subnet # # value. It's value will be a pointer that resolves to an offset outside # # the database. # # my $key_to_poison = key_for_data( { ip => '1.1.1.16' } ); # # my $orig_position_for_data # = MaxMind::DB::Writer::Serializer->can('_position_for_data'); # local *MaxMind::DB::Writer::Serializer::_position_for_data = sub { # my $key = $_[1]; # # if ( $key eq $key_to_poison ) { # return 1_000_000; # } # else { # return shift->$orig_position_for_data(@_); # } # }; # # write_test_db(@_); # # return; # } # sub write_broken_search_tree_db { # my $filename = ( write_test_db(@_) )[1]; # # my $content = read_binary($filename); # # # This causes the right record of the first node to be 0, meaning it # # points back to the top of the tree. This should never happen in a # # database that follows the spec. # substr( $content, 5, 1 ) = "\0"; # write_binary( $filename, $content ); # # return; # } # sub write_test_db { # my $record_size = shift; # my $subnets = shift; # my $metadata = shift; # my $ip_version_name = shift; # # my $writer = MaxMind::DB::Writer::Tree->new( # ip_version => $subnets->[0]->version(), # record_size => $record_size, # alias_ipv6_to_ipv4 => ( $subnets->[0]->version() == 6 ? 1 : 0 ), # map_key_type_callback => sub { 'utf8_string' }, # standard_test_metadata(), # %{$metadata}, # ); # # for my $subnet ( @{$subnets} ) { # $writer->insert_network( # $subnet, # { ip => $subnet->first()->as_string() } # ); # } # # my $filename = sprintf( # "$Dir/MaxMind-DB-test-%s-%i.mmdb", # $ip_version_name, # $record_size, # ); # open my $fh, '>', $filename; # # $writer->write_tree($fh); # # close $fh; # # return ( $writer, $filename ); # } # { # # We will store this once for each subnet so we will also be testing # # pointers, since the serializer will generate a pointer to this # # structure. # my %all_types = ( # utf8_string => 'unicode! ☯ - ♫', # double => 42.123456, # bytes => pack( 'N', 42 ), # uint16 => 100, # uint32 => 2**28, # int32 => -1 * ( 2**28 ), # uint64 => uint128(1) << 60, # uint128 => uint128(1) << 120, # array => [ 1, 2, 3, ], # map => { # mapX => { # utf8_stringX => 'hello', # arrayX => [ 7, 8, 9 ], # }, # }, # boolean => 1, # float => 1.1, # ); # # my %all_types_0 = ( # utf8_string => q{}, # double => 0, # bytes => q{}, # uint16 => 0, # uint32 => 0, # int32 => 0, # uint64 => uint128(0), # uint128 => uint128(0), # array => [], # map => {}, # boolean => 0, # float => 0, # ); # # # We limit this to numeric types as the other types would generate # # very large databases # my %numeric_types_max = ( # double => 'Inf', # float => 'Inf', # int32 => 0x7fffffff, # uint16 => 0xffff, # uint32 => string_to_uint128('0xffff_ffff'), # uint64 => string_to_uint128('0xffff_ffff_ffff_ffff'), # uint128 => MAX_UINT128, # ); # # sub write_decoder_test_db { # my $writer = _decoder_writer(); # # my @subnets # = map { Net::Works::Network->new_from_string( string => $_ ) } # qw( # ::1.1.1.0/120 # ::2.2.0.0/112 # ::3.0.0.0/104 # ::4.5.6.7/128 # abcd::/64 # 1000::1234:0000/112 # ); # # for my $subnet (@subnets) { # $writer->insert_network( # $subnet, # \%all_types, # ); # } # # $writer->insert_network( # Net::Works::Network->new_from_string( string => '::0.0.0.0/128' ), # \%all_types_0, # ); # # $writer->insert_network( # Net::Works::Network->new_from_string( # string => '::255.255.255.255/128' # ), # \%numeric_types_max, # ); # # open my $fh, '>', "$Dir/MaxMind-DB-test-decoder.mmdb"; # $writer->write_tree($fh); # close $fh; # # return; # } # # sub write_pointer_decoder_test_db { # # # We want to create a database where most values are pointers # no warnings 'redefine'; # local *MaxMind::DB::Writer::Serializer::_should_cache_value # = sub { 1 }; # my $writer = _decoder_writer(); # # # We add these slightly different records so that we end up with # # pointers for the individual values in the maps, not just pointers # # to the map # $writer->insert_network( # '1.0.0.0/32', # { # %all_types, # booleanX => 0, # arrayX => [ 1, 2, 3, 4, ], # mapXX => { # utf8_stringX => 'hello', # arrayX => [ 7, 8, 9, 10 ], # booleanX => 0, # }, # }, # ); # # $writer->insert_network( # '1.1.1.0/32', # { # %all_types, # # # This has to be 0 rather than 1 as otherwise the buggy # # Perl writer will think it is the same as an uint32 value of # # 1 and make a pointer to a value of a different type. # boolean => 0, # }, # ); # # open my $fh, '>', "$Dir/MaxMind-DB-test-pointer-decoder.mmdb"; # $writer->write_tree($fh); # close $fh; # # return; # } # # sub _decoder_writer { # return MaxMind::DB::Writer::Tree->new( # ip_version => 6, # record_size => 24, # database_type => 'MaxMind DB Decoder Test', # languages => ['en'], # description => { # en => # 'MaxMind DB Decoder Test database - contains every MaxMind DB data type', # }, # alias_ipv6_to_ipv4 => 1, # remove_reserved_networks => 0, # map_key_type_callback => sub { # my $key = $_[0]; # $key =~ s/X*$//; # return $key eq 'array' ? [ 'array', 'uint32' ] : $key; # }, # ); # } # } # { # my %nested = ( # map1 => { # map2 => { # array => [ # { # map3 => { a => 1, b => 2, c => 3 }, # }, # ], # }, # }, # ); # # sub write_deeply_nested_structures_db { # my $writer = MaxMind::DB::Writer::Tree->new( # ip_version => 6, # record_size => 24, # ip_version => 6, # database_type => 'MaxMind DB Nested Data Structures', # languages => ['en'], # description => { # en => # 'MaxMind DB Nested Data Structures Test database - contains deeply nested map/array structures', # }, # alias_ipv6_to_ipv4 => 1, # map_key_type_callback => sub { # my $key = shift; # return # $key =~ /^map/ ? 'map' # : $key eq 'array' ? [ 'array', 'map' ] # : 'uint32'; # } # ); # # my @subnets # = map { Net::Works::Network->new_from_string( string => $_ ) } # qw( # ::1.1.1.0/120 # ::2.2.0.0/112 # ::3.0.0.0/104 # ::4.5.6.7/128 # abcd::/64 # 1000::1234:0000/112 # ); # # for my $subnet (@subnets) { # $writer->insert_network( # $subnet, # \%nested, # ); # } # # open my $fh, '>', "$Dir/MaxMind-DB-test-nested.mmdb"; # $writer->write_tree($fh); # close $fh; # # return; # } # } sub write_geoip2_dbs { _write_geoip2_db( @{$_}[ 0, 1 ], 'Test' ) for ( # [ 'GeoIP2-Anonymous-IP', {} ], ['GeoIP2-City'], # ['GeoIP2-Connection-Type'], ['GeoIP2-Country'], # ['GeoIP2-DensityIncome'], # ['GeoIP2-Domain'], # ['GeoIP2-Enterprise'], ['GeoIP2-ISP'], # ['GeoIP2-Precision-Enterprise'], # ['GeoIP2-Static-IP-Score'], # ['GeoIP2-User-Count'], ['GeoLite2-ASN'], # ['GeoLite2-City'], # ['GeoLite2-Country'], ); } #sub write_broken_geoip2_city_db { # no warnings 'redefine'; # # # This is how we _used_ to encode doubles. Storing them this way with the # # current reader tools can lead to weird errors. This broken database is a # # good way to test the robustness of reader code in the face of broken # # databases. # local *MaxMind::DB::Writer::Serializer::_encode_double = sub { # my $self = shift; # my $value = shift; # # $self->_simple_encode( double => $value ); # }; # # _write_geoip2_db( 'GeoIP2-City', 0, 'Test Broken Double Format' ); #} #sub write_invalid_node_count { # no warnings 'redefine'; # local *MaxMind::DB::Writer::Tree::node_count = sub { 100000 }; # # _write_geoip2_db( 'GeoIP2-City', 0, 'Test Invalid Node Count' ); #} sub _universal_map_key_type_callback { my $map = { # languages de => 'utf8_string', en => 'utf8_string', es => 'utf8_string', fr => 'utf8_string', ja => 'utf8_string', 'pt-BR' => 'utf8_string', ru => 'utf8_string', 'zh-CN' => 'utf8_string', # production accuracy_radius => 'uint16', autonomous_system_number => 'uint32', autonomous_system_organization => 'utf8_string', average_income => 'uint32', city => 'map', code => 'utf8_string', confidence => 'uint16', connection_type => 'utf8_string', continent => 'map', country => 'map', domain => 'utf8_string', geoname_id => 'uint32', ipv4_24 => 'uint32', ipv4_32 => 'uint32', ipv6_32 => 'uint32', ipv6_48 => 'uint32', ipv6_64 => 'uint32', is_anonymous => 'boolean', is_anonymous_proxy => 'boolean', is_anonymous_vpn => 'boolean', is_hosting_provider => 'boolean', is_in_european_union => 'boolean', is_legitimate_proxy => 'boolean', is_public_proxy => 'boolean', is_residential_proxy => 'boolean', is_satellite_provider => 'boolean', is_tor_exit_node => 'boolean', iso_code => 'utf8_string', isp => 'utf8_string', latitude => 'double', location => 'map', longitude => 'double', metro_code => 'uint16', names => 'map', organization => 'utf8_string', population_density => 'uint32', #FIXME: Was 'uint32' but that makes the Java code crash! postal => 'map', registered_country => 'map', represented_country => 'map', score => 'double', static_ip_score => 'double', subdivisions => [ 'array', 'map' ], time_zone => 'utf8_string', traits => 'map', traits => 'map', type => 'utf8_string', user_type => 'utf8_string', # for testing only foo => 'utf8_string', bar => 'utf8_string', buzz => 'utf8_string', our_value => 'utf8_string', }; my $callback = sub { my $key = shift; return $map->{$key} || die <<"ERROR"; Unknown tree key '$key'. The universal_map_key_type_callback doesn't know what type to use for the passed key. If you are adding a new key that will be used in a frozen tree / mmdb then you should update the mapping in both our internal code and here. ERROR }; return $callback; } sub _write_geoip2_db { my $type = shift; my $populate_all_networks_with_data = shift; my $description = shift; my $writer = MaxMind::DB::Writer::Tree->new( ip_version => 6, record_size => 28, ip_version => 6, database_type => $type, languages => [ 'en', $type eq 'GeoIP2-City' ? ('zh') : () ], description => { en => ( $type =~ s/-/ /gr ) . " $description Database (fake GeoIP2 data, for example purposes only)", $type eq 'GeoIP2-City' ? ( zh => '小型数据库' ) : (), }, alias_ipv6_to_ipv4 => 1, map_key_type_callback => _universal_map_key_type_callback(), ); $writer->_set_build_epoch(1); # Fake timestamp to make the test files stable _populate_all_networks( $writer, $populate_all_networks_with_data ) if $populate_all_networks_with_data; my $value = shift; my $nodes = decode_json( read_binary("$Dir/../source-data/$type-Test.json") ); for my $node (@$nodes) { for my $network ( keys %$node ) { $writer->insert_network( Net::Works::Network->new_from_string( string => $network ), $node->{$network} ); } } my $suffix = $description =~ s/ /-/gr; open my $output_fh, '>', "$Dir/$type-$suffix.mmdb"; $writer->write_tree($output_fh); close $output_fh; return; } sub _populate_all_networks { my $writer = shift; my $data = shift; my $max_uint128 = uint128(0) - 1; my @networks = Net::Works::Network->range_as_subnets( Net::Works::Address->new_from_integer( integer => 0, version => 6, ), Net::Works::Address->new_from_integer( integer => $max_uint128, version => 6, ), ); for my $network (@networks) { $writer->insert_network( $network => $data ); } } # sub write_no_ipv4_tree_db { # my $subnets = shift; # # my $writer = MaxMind::DB::Writer::Tree->new( # ip_version => 6, # record_size => 24, # ip_version => 6, # database_type => 'MaxMind DB No IPv4 Search Tree', # languages => ['en'], # description => { # en => 'MaxMind DB No IPv4 Search Tree', # }, # remove_reserved_networks => 0, # root_data_type => 'utf8_string', # map_key_type_callback => sub { {} }, # ); # # my $subnet = Net::Works::Network->new_from_string( string => '::/64' ); # $writer->insert_network( $subnet, $subnet->as_string() ); # # open my $output_fh, '>', "$Dir/MaxMind-DB-no-ipv4-search-tree.mmdb"; # $writer->write_tree($output_fh); # close $output_fh; # # return; # } # The point of this database is to provide something where we can test looking # up a single value. In other words, each IP address points to a non-compound # value, a string rather than a map or array. # sub write_no_map_db { # my $subnets = shift; # # my $writer = MaxMind::DB::Writer::Tree->new( # ip_version => 4, # record_size => 24, # database_type => 'MaxMind DB String Value Entries', # languages => ['en'], # description => { # en => # 'MaxMind DB String Value Entries (no maps or arrays as values)', # }, # root_data_type => 'utf8_string', # map_key_type_callback => sub { {} }, # ); # # for my $subnet ( @{$subnets} ) { # $writer->insert_network( $subnet, $subnet->as_string() ); # } # # open my $output_fh, '>', "$Dir/MaxMind-DB-string-value-entries.mmdb"; # $writer->write_tree($output_fh); # close $output_fh; # # return; # } # sub write_test_serialization_data { # my $serializer = MaxMind::DB::Writer::Serializer->new( # map_key_type_callback => sub { 'utf8_string' } ); # # $serializer->store_data( map => { long_key => 'long_value1' } ); # $serializer->store_data( map => { long_key => 'long_value2' } ); # $serializer->store_data( map => { long_key2 => 'long_value1' } ); # $serializer->store_data( map => { long_key2 => 'long_value2' } ); # $serializer->store_data( map => { long_key => 'long_value1' } ); # $serializer->store_data( map => { long_key2 => 'long_value2' } ); # # open my $fh, '>', 'maps-with-pointers.raw'; # print {$fh} ${ $serializer->buffer() } # or die "Cannot write to maps-with-pointers.raw: $!"; # close $fh; # # return; # } # sub write_db_with_metadata_pointers { # my $repeated_string = 'Lots of pointers in metadata'; # my $writer = MaxMind::DB::Writer::Tree->new( # ip_version => 6, # record_size => 24, # map_key_type_callback => sub { 'utf8_string' }, # database_type => $repeated_string, # languages => [ 'en', 'es', 'zh' ], # description => { # en => $repeated_string, # es => $repeated_string, # zh => $repeated_string, # }, # # ); # # _populate_all_networks( $writer, {} ); # # open my $fh, '>', 'MaxMind-DB-test-metadata-pointers.mmdb'; # # $writer->write_tree($fh); # # close $fh; # } main(); ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README-Hive.md ================================================ Hive ==== The SerDe (it's really only a Deserializer) can be used present an Apache HTTPD logfile as a table in Hive. This is an annotated example on how you could make the logfiles directly accessible through Hive. First we must ensure that Hive has the right jar file available. This can be either using the ADD JAR option in the Hive Cli or by installing it on the cluster. ADD JAR target/httpdlog-serde-*-udf.jar; We can now define an external table with column types are STRING, BIGINT and DOUBLE. CREATE EXTERNAL TABLE nbasjes.clicks ( ip STRING ,timestamp BIGINT ,useragent STRING ,referrer STRING ,bui STRING ,screenHeight BIGINT ,screenWidth BIGINT ) Of course we must specify the class name of the Deserializer that does the heavy lifting. ROW FORMAT SERDE 'nl.basjes.parse.apachehttpdlog.ApacheHttpdlogDeserializer' The big part of the config lies in the SERDEPROPERTIES. There are currently 4 types of options you can/must put in there: - "logformat" = "[Apache httpd logformat]" - "field:[columnname]" = "[Field]" - "map:[field]" = "[new type]" - "load:[classname that implements Dissector]" = "[initialization string send to the initializeFromSettingsParameter method]" Note that the order of various settings in the SERDEPROPERTIES is irrelevant. WITH SERDEPROPERTIES ( **"logformat" = "[Apache httpd logformat]"** This is the Logformat specification straight from the apache httpd config file. "logformat" = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" %T %V" **"field:[columnname]" = "[Field]"** For each column this type of property is needed for the system to know where to get the content from. ,"field:timestamp" = "TIME.EPOCH:request.receive.time.epoch" ,"field:ip" = "IP:connection.client.host" ,"field:useragent" = "HTTP.USERAGENT:request.user-agent" **"map:[field]" = "[new type]"** Only used when mapping a specific field to a different type. ,"map:request.firstline.uri.query.g"="HTTP.URI" ,"map:request.firstline.uri.query.r"="HTTP.URI" ,"field:referrer" = "STRING:request.firstline.uri.query.g.query.referrer" ,"field:bui" = "HTTP.COOKIE:request.cookies.bui" **"load:[classname that implements Dissector]" = "[initialization string send to the initializeFromSettingsParameter method]"** Only used when there is a custom Dissector implementation that needs to be loaded in addition to the regular Dissectors. ,"load:nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector" = "x" ,"map:request.firstline.uri.query.s" = "SCREENRESOLUTION" ,"field:screenHeight" = "SCREENHEIGHT:request.firstline.uri.query.s.height" ,"field:screenWidth" = "SCREENWIDTH:request.firstline.uri.query.s.width" ) Finally we define that this is stored as a TEXTFILE and where the files are located. STORED AS TEXTFILE LOCATION "/user/nbasjes/clicks"; Complete example ==== ADD JAR target/httpdlog-serde-*-udf.jar; CREATE EXTERNAL TABLE nbasjes.clicks ( ip STRING ,timestamp BIGINT ,useragent STRING ,referrer STRING ,bui STRING ,screenHeight BIGINT ,screenWidth BIGINT ) ROW FORMAT SERDE 'nl.basjes.parse.apachehttpdlog.ApacheHttpdlogDeserializer' WITH SERDEPROPERTIES ( "logformat" = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" %T %V" ,"field:timestamp" = "TIME.EPOCH:request.receive.time.epoch" ,"field:ip" = "IP:connection.client.host" ,"field:useragent" = "HTTP.USERAGENT:request.user-agent" ,"map:request.firstline.uri.query.g"="HTTP.URI" ,"map:request.firstline.uri.query.r"="HTTP.URI" ,"field:referrer" = "STRING:request.firstline.uri.query.g.query.referrer" ,"field:bui" = "HTTP.COOKIE:request.cookies.bui" ,"load:nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector" = "x" ,"map:request.firstline.uri.query.s" = "SCREENRESOLUTION" ,"field:screenHeight" = "SCREENHEIGHT:request.firstline.uri.query.s.height" ,"field:screenWidth" = "SCREENWIDTH:request.firstline.uri.query.s.width" ) STORED AS TEXTFILE LOCATION "/user/nbasjes/clicks"; License === Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README-Java.md ================================================ Apache HTTPD logparser === This is a Logparsing framework intended to make parsing Apache HTTPD logfiles much easier. The basic idea is that you should be able to have a parser that you can construct by simply telling it with what configuration options the line was written. Usage (Java) === For the Java API there is an annotation based parser. First you put something like this in your pom.xml file: nl.basjes.parse.httpdlog httpdlog-parser 6.0.0 I assume we have a logformat variable that looks something like this: String logformat = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""; **Step 1: What CAN we get from this line?** To figure out what values we CAN get from this line we instantiate the parser with a dummy class that does not have ANY @Field annotations. The "Object" class will do just fine for this purpose. Parser dummyParser = new HttpdLoglineParser(Object.class, logformat); List possiblePaths = dummyParser.getPossiblePaths(); for (String path: possiblePaths) { System.out.println(path); } You will get a list that looks something like this: IP:connection.client.host NUMBER:connection.client.logname STRING:connection.client.user TIME.STAMP:request.receive.time TIME.DAY:request.receive.time.day TIME.MONTHNAME:request.receive.time.monthname TIME.MONTH:request.receive.time.month TIME.YEAR:request.receive.time.year TIME.HOUR:request.receive.time.hour TIME.MINUTE:request.receive.time.minute TIME.SECOND:request.receive.time.second TIME.MILLISECOND:request.receive.time.millisecond TIME.ZONE:request.receive.time.timezone HTTP.FIRSTLINE:request.firstline HTTP.METHOD:request.firstline.method HTTP.URI:request.firstline.uri HTTP.QUERYSTRING:request.firstline.uri.query STRING:request.firstline.uri.query.* HTTP.PROTOCOL:request.firstline.protocol HTTP.PROTOCOL.VERSION:request.firstline.protocol.version STRING:request.status.last BYTESCLF:response.body.bytes HTTP.URI:request.referer HTTP.QUERYSTRING:request.referer.query STRING:request.referer.query.* HTTP.USERAGENT:request.user-agent Now some of these lines contain a * . This is a wildcard that can be replaced with any 'name' if you need a specific value. You can also leave the '*' and get everything that is found in the actual log line. **Step 2 Create the receiving POJO** We need to create the receiving record class that is simply a POJO that does not need any interface or inheritance. In this class we create setters that will be called when the specified field has been found in the line. So we can now add to this class a setter that simply receives a single value: @Field("IP:connection.client.host") public void setIP(final String value) { ip = value; } If we really want the name of the field we can also do this @Field("STRING:request.firstline.uri.query.img") public void setQueryImg(final String name, final String value) { results.put(name, value); } This latter form is very handy because this way we can obtain all values for a wildcard field @Field("STRING:request.firstline.uri.query.*") public void setQueryStringValues(final String name, final String value) { results.put(name, value); } Or a combination of the above examples where you specify multiple field patterns @Field({"IP:connection.client.host", "STRING:request.firstline.uri.query.*"}) public void setValue(final String name, final String value) { results.put(name, value); } In some cases you may not want to have empty/null values so starting with version 5.0 you can specify a setterPolicy: @Field(value = "STRING:request.firstline.uri.query.*", setterPolicy = NOT_NULL) The 3 possible values for the setterPolicy flag are: ALWAYS : Call the setter for all values: Normal, Empty and NULL. NOT_NULL : Call the setter for values: Normal and Empty, but not for NULL values. NOT_EMPTY : Call the setter for values: Normal, but not for Empty and NULL values. *Notes about the setters* - Only if a value exists in the actual logline the setter will be called (mainly relevant if you want to get a specific query param or cookie). - If you specifiy the same field on several setters then each of these setters will be called. - There is NO guarantee about the order the setters will be called. Have a look at the 'examples/pojo' directory for a working example. **Step 3 Use the parser in your application.** You create an instance of the parser Parser parser = new HttpdLoglineParser(MyRecord.class, logformat); And then call the parse method repeatedly for each line. There are two ways to do this: 1) Let the parser create and a new instance of "MyRecord" for each parsed line (think about the GC consequences!!): MyRecord record = parser.parse(logline); 2) Reuse the same instance. So you do this only once: MyRecord record = new MyRecord(); And then for each logline: record.clear(); // Which is up to you to implement to 'reset' the record instance to it's initial/empty state. parser.parse(record, logline); Project Lombok === In case you like to use project Lombok to generate your getters and setters then using the annotations looks something like this: @Getter @Setter(onMethod=@__(@Field("HTTP.COOKIE:request.cookies.foo"))) private String foo = null; To avoid weird effects please install the "Lombok Plugin" in IntelliJ IDEA to use this. License === Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README-Pig.md ================================================ Abandoned! === Version 5.8 is the last version to support Apache Pig. The last release of Apache Pig was in 2017 and right now (2023) the tool is effectively no longer used by anyone. License === Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README-geoip.md ================================================ Dissect IP using GeoIP2 information === This project also contains a dissector that uses the [MaxMind](https://www.maxmind.com) GeoIP2 data to dissect IP addresses into things like Country, City, ASN, etc. Where are the datafiles? --- Simple: I didn't include them. The data is owned by MaxMind and in order to use it you must either purchase a license for 'accurate' GeoIP2 data or download a 'slightly less accurate' free GeoLite2 version. Also adding these files would make the repo very big. See https://dev.maxmind.com/ for the both the paid GeoIP2 and the free GeoLite2 downloadable databases. I personally install and run the geoipupdate tool. https://dev.maxmind.com/geoip/geoipupdate/ The datafiles I usually work with: /var/lib/GeoIP/GeoLite2-City.mmdb /var/lib/GeoIP/GeoLite2-Country.mmdb /var/lib/GeoIP/GeoIP2-ISP.mmdb /var/lib/GeoIP/GeoLite2-ASN.mmdb You can get some of those by installing geoipupdate tool with the config file /etc/GeoIP.conf # The following UserId and LicenseKey are required placeholders: UserId 999999 LicenseKey 000000000000 ProductIds GeoLite2-City GeoLite2-Country GeoLite2-ASN How do I use it? === Currently there are 4 dissectors available ASN --- * Class: nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPASNDissector * Input: Needs the path to the GeoLite2-ASN.mmdb to function. * Output: ASN number and organization. ISP --- * Class: nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector * Input: Needs the path to the GeoIP2-ISP.mmdb or GeoLite2-ISP.mmdb to function. * Output: ASN number and organization, ISP name and organization. Country --- * Class: nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCountryDissector * Input: Needs the path to the GeoIP2-Country.mmdb or GeoLite2-Country.mmdb to function. * Output: Information about continent and country. City --- * Class: nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector * Input: Needs the path to the GeoIP2-City.mmdb or GeoLite2-City.mmdb to function. * Output: Information about continent, country, subdivision, city, postalcode and latitude/longitude. License === Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: README.md ================================================ Apache HTTPD & NGINX access log parser ====================================== [![Github actions Build status](https://img.shields.io/github/actions/workflow/status/nielsbasjes/logparser/build.yml?branch=main)](https://github.com/nielsbasjes/logparser/actions) [![Coverage Status](https://img.shields.io/codecov/c/github/nielsbasjes/logparser)](https://app.codecov.io/gh/nielsbasjes/logparser) [![License](https://img.shields.io/:license-apache-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Maven Central](https://img.shields.io/maven-central/v/nl.basjes.parse/parser-parent.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22nl.basjes.parse.httpdlog%22) [![If this project has business value for you then don't hesitate to support me with a small donation.](https://img.shields.io/badge/Sponsor%20me-via%20Github-red.svg)](https://github.com/sponsors/nielsbasjes) [![If this project has business value for you then don't hesitate to support me with a small donation.](https://img.shields.io/badge/Donations-via%20Paypal-red.svg)](https://www.paypal.me/nielsbasjes) This is a Logparsing framework intended to make parsing [Apache HTTPD](https://httpd.apache.org/) and [NGINX](https://nginx.org/) access log files much easier. The basic idea is that you should be able to have a parser that you can construct by simply telling it with what configuration options the line was written. These configuration options are the schema of the access loglines. So we are using the LogFormat that wrote the file as the input parameter for the parser that reads the same file. In addition to the config options specified in the Apache HTTPD manual under [Custom Log Formats](https://httpd.apache.org/docs/current/mod/mod_log_config.html) the following are also recognized: * common * combined * combinedio * referer * agent For Nginx the log_format tokens are specified [here](https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format) and [here](https://nginx.org/en/docs/http/ngx_http_core_module.html#variables). **Special notes about the Apache HTTPD token %{format}t** === Quote from [Apache HTTPD manual](https://httpd.apache.org/docs/current/mod/mod_log_config.html#formats) %{format}t: The time, in the form given by format, which should be in strftime(3) format. (potentially localized) * **Version 2.5 and before**: It cannot be extracted. A simple workaround for this limitation: replace the **%{...}t** with **%{timestamp}i** . You will then get this timestamp field as if it was a request header: HTTP.HEADER:request.header.timestamp * **Version 2.6 and newer**: You will receive it as a textual *TIME.LOCALIZEDSTRING:request.header.time* which cannot be extracted any further. * **Version 3.0 and newer**: Support for parsing the customized time as long as all elements can be mapped to fields supported by joda-time. This means that many fields are supported, but not all. Check the implementation in the [StrfTimeStampDissector](../v3.1/httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/StrfTimeStampDissector.java#L140) class to see which are and are not supported. * **Version 4.0 and newer**: Switched to parsing using native java 8 time library supports a few fields differently. See [StrfTimeToDateTimeFormatter](/httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/StrfTimeToDateTimeFormatter.java#L119). **Limitation**: Only a single %{format}t entry is supported per line. Examples as described in the LogFormat [examples section](https://httpd.apache.org/docs/current/mod/mod_log_config.html#examples) of the Apache HTTPD manual cannot be parsed. You can use the %{format}t directive multiple times to build up a time format using the extended format tokens like msec_frac: Timestamp including milliseconds "%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t" In this case where all %{format}t fields are only separated by fixed text you can rewrite this example like this "%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t" "%{%d/%b/%Y %T.msec_frac %z}t" Although the latter is NOT supported by Apache HTTPD this IS supported by this logparser so the above works as expected. Analyze almost anything === I wrote this parser for practical reallife situations. In reality a lot happens that is not allowed when looking at the official specifications, yet in production they do happen. So several of the key parts in this parser try to recover from bad data where possible and thus allow to extract as much useful information as possible even if the data is not valid. Important examples of this are invalid encoding characters and chopped multibyte encoded characters that are both extracted as best as possible. If you have a real logline that causes a parse error then I kindly request you to submit this line, the logformat and the field that triggered the error as a bug report. Pre built versions === Prebuilt versions have been deployed to maven central so using it in a project is as simple as adding a dependency. So using it in a Java based project is as simple as adding this to your dependencies nl.basjes.parse.httpdlog httpdlog-parser 6.0.0 Note that starting with version 6.0.0 Java 21 is needed as a runtime because of several dependencies that have updated to that. Building === Simply type : mvn package and the whole thing should build. Java, Apache {Hadoop, Hive, Drill, Flink, Beam} === I'm a big user of bigdata tools like Apache Hadoop, Hive, etc. . So in here are also a Hadoop inputformat and a Hive/HCatalog Serde that are wrappers around this library. Usage (Overview) === The framework needs two things: * The format specification in which the logfile was written (straight from the original apache httpd config file). * The identifiers for the fields that you want. To obtain all the identifiers the system CAN extract from the specified logformat a separate developer call exists in various languages that allows you to get the list of all possible values. Languages and Tools === The languages that are supported in this version: * [Java](README-Java.md) Prebuilt plugins for these are provided in the distribution: * [Apache Hive](README-Hive.md) For tools like Apache Flink and Beam there is only example code that is also used to verify that the build still works on those systems. * [Apache Flink](examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink) * [Apache Beam](examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam) Tools that ship a version of this parser in their distribution * ~~[Apache Pig](https://github.com/apache/pig/blob/trunk/contrib/piggybank/java/src/main/java/org/apache/pig/piggybank/storage/apachelog/LogFormatLoader.java)~~ * [Apache Drill](https://drill.apache.org/docs/httpd-format-plugin/) Internal structure and type remapping === The basic model of this system is a tree. Each node in the tree has a 'type' and a 'name'. The 'type' is really a 'what is the format of this string' indicator. Because there are many more of those kinds of types than your average String or Long you will see a lot of different names. The 'name' is the "breadbrumb" towards the point in the tree where this is located. A 'Dissector' is a class that can cut a specific type (format) into a bunch of new parts that each extend the base name and have their own type. Because an internal parser is constructed at the start of running a parser this tree has some dynamic properties. To start only the tree is constructed for the elements actually requested. This is done to avoid 'dissecting' something that is not wanted. So the parser will have a different structure depending on the requested output. These dynamic properties also allow 'mapping a field to a different type'. Lets illustrate what this is by looking at the most common usecase. Assume you are trying to parse the logline for a pixel that was written by a webanalytics product. In that scenario it is common that the URL is that of a pixel and one of the query string parameters contains the actual URL. Now by default a querystring parameter gets the type STRING (which really means that is is arbitrary and cannot be dissected any further). Using this remapping (see API details per language) we can now say that a specific query string parameter really has the type HTTP.URL. As a consequence the system can now continue dissecting this specific query string parameter into things like the host, port and query string parameters. All that is needed to map the 'g' and 'r' parameters so they are dissected further is this: Java: Call these against the parser instance right after construction parser.addTypeRemapping("request.firstline.uri.query.g", "HTTP.URI", Casts.STRING_ONLY); parser.addTypeRemapping("request.firstline.uri.query.r", "HTTP.URI", Casts.STRING_ONLY); Hive: Add these to the SERDEPROPERTIES "map:request.firstline.uri.query.g"="HTTP.URI", "map:request.firstline.uri.query.r"="HTTP.URI", Special Dissectors === **mod_unique_id** If you have a log field / request header that gets filled using mod_unique_id you can now peek inside the values that were used to construct this. **NOTE: https://httpd.apache.org/docs/current/mod/mod_unique_id.html clearly states** it should be emphasized that applications should not dissect the encoding. Applications should treat the entire encoded UNIQUE_ID as an opaque token, which can be compared against other UNIQUE_IDs for equality only. When you choose to ignore the clear 'should not' statement then simply add a type remapping to map the field to the type *MOD_UNIQUE_ID* **GeoIP parsing** Head for the separate [README](README-geoip.md) file for information about this dissector. Parsing problems with Jetty generated logfiles ============================================== In Jetty there is the option to create a logfile in what they call the NCSARequestLog format. It was found that (historically) this had two formatting problems which cause parse errors: 1. If the useragent is missing the empty value is logged with an extra ' ' after it. The fix for this in Jetty was committed on 2016-07-27 in the Jetty 9.3.x and 9.4.x branches 2. Before jetty-9.2.4.v20141103 if there is no user available the %u field is logged as " - " (i.e. with two extra spaces around the '-'). To workaround these problems you can easily start the parser with a two line logformat: ENABLE JETTY FIX %h %l %u %t \"%r\" %>s %b "%{Referer}i" "%{User-Agent}i" %D This *ENABLE JETTY FIX* is a 'magic' value that causes the underlying parser to enable the workaround for both of these problems. In order for this to work correctly the useragent field must look exactly like this: *"%{User-Agent}i"* Donations === If this project has business value for you then don't hesitate to support me with a small donation. [![If this project has business value for you then don't hesitate to support me with a small donation.](https://img.shields.io/badge/Sponsor%20me-via%20Github-red.svg)](https://github.com/sponsors/nielsbasjes) [![If this project has business value for you then don't hesitate to support me with a small donation.](https://img.shields.io/badge/Donations-via%20Paypal-red.svg)](https://www.paypal.me/nielsbasjes) License === Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: _config.yml ================================================ theme: jekyll-theme-cayman ================================================ FILE: devtools/docker/Dockerfile ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # FROM ubuntu:26.04 WORKDIR /root ENV INSIDE_DOCKER Yes ARG DEBIAN_FRONTEND=noninteractive WORKDIR /root SHELL ["/bin/bash", "-o", "pipefail", "-c"] ##### # Disable suggests/recommends ##### RUN echo APT::Install-Recommends "0"\; > /etc/apt/apt.conf.d/10disableextras RUN echo APT::Install-Suggests "0"\; >> /etc/apt/apt.conf.d/10disableextras ENV DEBIAN_FRONTEND noninteractive ENV DEBCONF_TERSE true ### # Update and install common packages ### RUN apt -q update \ && apt install -y software-properties-common apt-utils apt-transport-https ca-certificates \ && add-apt-repository -y ppa:deadsnakes/ppa RUN apt-get -q install -y --no-install-recommends \ bash-completion \ build-essential \ bzip2 \ wget \ curl \ docker.io \ git \ gnupg-agent \ rsync \ sudo \ vim \ locales \ wget \ time \ ruby \ openjdk-8-jdk \ openjdk-11-jdk \ openjdk-17-jdk ### # Set the locale ( see https://stackoverflow.com/a/28406007/114196 ) ### RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && \ locale-gen ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 # -------------------------------- # Install Maven ENV MAVEN_VERSION=3.8.3 RUN mkdir -p /usr/local/apache-maven RUN cd /usr/local/ && wget "https://www.apache.org/dyn/closer.lua?action=download&filename=/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" -O "apache-maven-${MAVEN_VERSION}-bin.tar.gz" RUN cd /usr/local/ && tar xzf apache-maven-${MAVEN_VERSION}-bin.tar.gz --strip-components 1 -C /usr/local/apache-maven ENV M2_HOME /usr/local/apache-maven ENV PATH ${M2_HOME}/bin:${PATH} # Avoid out of memory errors in builds ENV MAVEN_OPTS -Xms256m -Xmx512m # Install command line completion for maven RUN wget https://raw.githubusercontent.com/juven/maven-bash-completion/master/bash_completion.bash -O /etc/bash_completion.d/maven # -------------------------------- # Install shellcheck RUN cd /usr/local/bin && \ wget https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.linux.x86_64.tar.xz && \ tar xJf shellcheck-stable.linux.x86_64.tar.xz && \ mv shellcheck-stable/shellcheck . && \ rm -rf shellcheck-stable* # -------------------------------- # Install Hugo ENV HUGO_VERSION=0.89.0 RUN cd /usr/local/bin && \ wget https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz && \ tar xzf hugo_*.tar.gz # -------------------------------- # Add a welcome message and environment checks. RUN mkdir /scripts ADD *.sh /scripts/ RUN chmod 755 /scripts/*.sh # -------------------------------- # For serving the documentation site EXPOSE 1313 ================================================ FILE: devtools/docker/bashcolors.sh ================================================ #!/bin/bash # # Yet Another UserAgent Analyzer # Copyright (C) 2013-2022 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an AS IS BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #https://wiki.archlinux.org/index.php/Color_Bash_Prompt # Reset export Color_Off='\e[0m' # Text Reset # Regular Colors export Black='\e[0;30m' # Black export Red='\e[0;31m' # Red export Green='\e[0;32m' # Green export Yellow='\e[0;33m' # Yellow export Blue='\e[0;34m' # Blue export Purple='\e[0;35m' # Purple export Cyan='\e[0;36m' # Cyan export White='\e[0;37m' # White # Bold export BBlack='\e[1;30m' # Black export BRed='\e[1;31m' # Red export BGreen='\e[1;32m' # Green export BYellow='\e[1;33m' # Yellow export BBlue='\e[1;34m' # Blue export BPurple='\e[1;35m' # Purple export BCyan='\e[1;36m' # Cyan export BWhite='\e[1;37m' # White # Underline export UBlack='\e[4;30m' # Black export URed='\e[4;31m' # Red export UGreen='\e[4;32m' # Green export UYellow='\e[4;33m' # Yellow export UBlue='\e[4;34m' # Blue export UPurple='\e[4;35m' # Purple export UCyan='\e[4;36m' # Cyan export UWhite='\e[4;37m' # White # Background export On_Black='\e[40m' # Black export On_Red='\e[41m' # Red export On_Green='\e[42m' # Green export On_Yellow='\e[43m' # Yellow export On_Blue='\e[44m' # Blue export On_Purple='\e[45m' # Purple export On_Cyan='\e[46m' # Cyan export On_White='\e[47m' # White # High Intensity export IBlack='\e[0;90m' # Black export IRed='\e[0;91m' # Red export IGreen='\e[0;92m' # Green export IYellow='\e[0;93m' # Yellow export IBlue='\e[0;94m' # Blue export IPurple='\e[0;95m' # Purple export ICyan='\e[0;96m' # Cyan export IWhite='\e[0;97m' # White # Bold High Intensity export BIBlack='\e[1;90m' # Black export BIRed='\e[1;91m' # Red export BIGreen='\e[1;92m' # Green export BIYellow='\e[1;93m' # Yellow export BIBlue='\e[1;94m' # Blue export BIPurple='\e[1;95m' # Purple export BICyan='\e[1;96m' # Cyan export BIWhite='\e[1;97m' # White # High Intensity backgrounds export On_IBlack='\e[0;100m' # Black export On_IRed='\e[0;101m' # Red export On_IGreen='\e[0;102m' # Green export On_IYellow='\e[0;103m' # Yellow export On_IBlue='\e[0;104m' # Blue export On_IPurple='\e[0;105m' # Purple export On_ICyan='\e[0;106m' # Cyan export On_IWhite='\e[0;107m' # White ================================================ FILE: devtools/docker/build_env_checks.sh ================================================ #!/bin/bash # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # ------------------------------------------------------- function showWelcome { # http://patorjk.com/software/taag/#p=display&f=Slant&t=LogParser%20Builder cat << "Welcome-message" __ ____ ____ _ __ __ / / ____ ____ _/ __ \____ ______________ _____ / __ )__ __(_) /___/ /__ _____ / / / __ \/ __ `/ /_/ / __ `/ ___/ ___/ _ \/ ___/ / __ / / / / / / __ / _ \/ ___/ / /___/ /_/ / /_/ / ____/ /_/ / / (__ ) __/ / / /_/ / /_/ / / / /_/ / __/ / /_____/\____/\__, /_/ \__,_/_/ /____/\___/_/ /_____/\__,_/_/_/\__,_/\___/_/ /____/ This is the standard LogParser build environment. In here all tools needed to run a build are present. Welcome-message } # ------------------------------------------------------- function showAbort { # http://patorjk.com/software/taag/#p=display&f=Doom&t=Aborting... cat << "Abort-message" ___ _ _ _ / _ \| | | | (_) / /_\ \ |__ ___ _ __| |_ _ _ __ __ _ | _ | '_ \ / _ \| '__| __| | '_ \ / _` | | | | | |_) | (_) | | | |_| | | | | (_| |_ _ _ \_| |_/_.__/ \___/|_| \__|_|_| |_|\__, (_|_|_) __/ | |___/ Abort-message } # ------------------------------------------------------- function failIfUserIsRoot { if [ "$(id -u)" -eq "0" ]; # If you are root then something went wrong. then cat <> "/home/${USER_NAME}/.bashrc" VBOXSF_GROUP_LINE=$4 if [[ -n "${VBOXSF_GROUP_LINE}" ]]; then echo "${VBOXSF_GROUP_LINE}" >> /etc/group usermod -aG vboxsf "${USER_NAME}" fi echo "${USER_NAME} ALL=(ALL) NOPASSWD: ALL" >> "/etc/sudoers.d/${USER_NAME}" ================================================ FILE: devtools/docker/env.sh ================================================ #!/bin/bash # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an AS IS BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # . "/scripts/build_env_checks.sh" . "/scripts/bashcolors.sh" export JDK_VERSION="???" function __INTERNAL__SwitchJDK { JDK=$1 echo -e "${IRed}${On_Black}Setting JDK to version ${JDK}${Color_Off}" sudo update-java-alternatives --set $(update-java-alternatives -l | fgrep "${JDK}" | sed 's@ \+@ @g' | cut -d' ' -f1); export JAVA_HOME=$(update-java-alternatives -l | fgrep "${JDK}" | sed 's@ \+@ @g' | cut -d' ' -f3); # export JDK_VERSION="JDK ${JDK}" } echo "Use switch-jdk8, switch-jdk11 or switch-jdk17 to select the desired JDK to build with." alias switch-jdk8="__INTERNAL__SwitchJDK 1.8.0; export JDK_VERSION=JDK-8" alias switch-jdk11="__INTERNAL__SwitchJDK 1.11.0; export JDK_VERSION=JDK-11" alias switch-jdk17="__INTERNAL__SwitchJDK 1.17.0 ; export JDK_VERSION=JDK-17" #alias switch-jdk13="__INTERNAL__SwitchJDK latest; export JDK_VERSION=JDK-13" switch-jdk11 . "/usr/lib/git-core/git-sh-prompt" export PS1='\['${IBlue}${On_Black}'\] \u@\['${IWhite}${On_Red}'\][Yauaa Builder \['${BWhite}${On_Blue}'\]<'\${JDK_VERSION}'>\['${IWhite}${On_Red}'\]]\['${IBlue}${On_Black}'\]:\['${Cyan}${On_Black}'\]\w$(declare -F __git_ps1 &>/dev/null && __git_ps1 " \['${BIPurple}'\]{\['${BIGreen}'\]%s\['${BIPurple}'\]}")\['${BIBlue}'\] ]\['${Color_Off}'\]\n$ ' alias documentation-serve="cd ~/yauaa/documentation && hugo server -b http://localhost --bind=0.0.0.0" ================================================ FILE: devtools/docker/prompt.sh ================================================ #!/bin/bash # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an AS IS BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #https://wiki.archlinux.org/index.php/Color_Bash_Prompt # Reset Color_Off='\e[0m' # Text Reset # Regular Colors #Black='\e[0;30m' # Black #Red='\e[0;31m' # Red #Green='\e[0;32m' # Green #Yellow='\e[0;33m' # Yellow #Blue='\e[0;34m' # Blue #Purple='\e[0;35m' # Purple Cyan='\e[0;36m' # Cyan #White='\e[0;37m' # White # Bold #BBlack='\e[1;30m' # Black #BRed='\e[1;31m' # Red #BGreen='\e[1;32m' # Green #BYellow='\e[1;33m' # Yellow #BBlue='\e[1;34m' # Blue #BPurple='\e[1;35m' # Purple #BCyan='\e[1;36m' # Cyan #BWhite='\e[1;37m' # White # Underline #UBlack='\e[4;30m' # Black #URed='\e[4;31m' # Red #UGreen='\e[4;32m' # Green #UYellow='\e[4;33m' # Yellow #UBlue='\e[4;34m' # Blue #UPurple='\e[4;35m' # Purple #UCyan='\e[4;36m' # Cyan #UWhite='\e[4;37m' # White # Background On_Black='\e[40m' # Black On_Red='\e[41m' # Red #On_Green='\e[42m' # Green #On_Yellow='\e[43m' # Yellow #On_Blue='\e[44m' # Blue #On_Purple='\e[45m' # Purple #On_Cyan='\e[46m' # Cyan #On_White='\e[47m' # White # High Intensity #IBlack='\e[0;90m' # Black #IRed='\e[0;91m' # Red #IGreen='\e[0;92m' # Green #IYellow='\e[0;93m' # Yellow IBlue='\e[0;94m' # Blue #IPurple='\e[0;95m' # Purple #ICyan='\e[0;96m' # Cyan IWhite='\e[0;97m' # White # Bold High Intensity #BIBlack='\e[1;90m' # Black #BIRed='\e[1;91m' # Red BIGreen='\e[1;92m' # Green #BIYellow='\e[1;93m' # Yellow BIBlue='\e[1;94m' # Blue BIPurple='\e[1;95m' # Purple #BICyan='\e[1;96m' # Cyan #BIWhite='\e[1;97m' # White # High Intensity backgrounds #On_IBlack='\e[0;100m' # Black #On_IRed='\e[0;101m' # Red #On_IGreen='\e[0;102m' # Green #On_IYellow='\e[0;103m' # Yellow #On_IBlue='\e[0;104m' # Blue #On_IPurple='\e[0;105m' # Purple #On_ICyan='\e[0;106m' # Cyan #On_IWhite='\e[0;107m' # White export PS1='\['${IBlue}${On_Black}'\] \u@\['${IWhite}${On_Red}'\][LogParser Builder]\['${IBlue}${On_Black}'\]:\['${Cyan}${On_Black}'\]\w$(declare -F __git_ps1 &>/dev/null && __git_ps1 " \['${BIPurple}'\]{\['${BIGreen}'\]%s\['${BIPurple}'\]}")\['${BIBlue}'\] ]\['${Color_Off}'\]\n$ ' ================================================ FILE: devtools/logformat.conf ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # For testing (almost) all log format specifiers LogFormat "\"%%\" \"%a\" \"%{c}a\" \"%A\" \"%B\" \"%b\" \"%D\" \"%f\" \"%h\" \"%H\" \"%k\" \"%l\" \"%L\" \"%m\" \"%p\" \"%{canonical}p\" \"%{local}p\" \"%{remote}p\" \"%P\" \"%{pid}P\" \"%{tid}P\" \"%{hextid}P\" \"%q\" \"%r\" \"%R\" \"%s\" \"%>s\" \"%t\" \"%{msec}t\" \"%{begin:msec}t\" \"%{end:msec}t\" \"%{usec}t\" \"%{begin:usec}t\" \"%{end:usec}t\" \"%{msec_frac}t\" \"%{begin:msec_frac}t\" \"%{end:msec_frac}t\" \"%{usec_frac}t\" \"%{begin:usec_frac}t\" \"%{end:usec_frac}t\" \"%T\" \"%u\" \"%U\" \"%v\" \"%V\" \"%X\" \"%I\" \"%O\" \"%{cookie}i\" \"%{set-cookie}o\" \"%{user-agent}i\" \"%{referer}i\"" logEverything CustomLog "logs/fullaccess_log" logEverything "%" "172.17.42.1" "172.17.42.1" "172.17.0.2" "4880" "4880" "652" "/usr/share/httpd/noindex/index.html" "172.17.42.1" "HTTP/1.1" "0" "-" "VG9exZ0MX@uqta4OldejvQAAAAA" "GET" "80" "80" "80" "43417" "126" "126" "140597540726848" "140597540726848" "" "GET / HTTP/1.1" "httpd/unix-directory" "403" "403" "[21/Nov/2014:15:48:21 +0000]" "1416584901018" "1416584901018" "1416584901018" "1416584901018010" "1416584901018010" "1416584901018670" "018" "018" "018" "018010" "018010" "018670" "0" "-" "/" "172.17.0.2" "172.17.0.2" "+" "367" "5188" "-" "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36" "-" "%" "172.17.42.1" "172.17.42.1" "172.17.0.2" "0" "-" "302" "/usr/share/httpd/noindex/css/bootstrap.min.css" "172.17.42.1" "HTTP/1.1" "1" "-" "-" "GET" "80" "80" "80" "43417" "126" "126" "140597540726848" "140597540726848" "" "GET /css/bootstrap.min.css HTTP/1.1" "-" "304" "304" "[21/Nov/2014:15:48:21 +0000]" "1416584901087" "1416584901087" "1416584901087" "1416584901087115" "1416584901087115" "1416584901087417" "087" "087" "087" "087115" "087115" "087417" "0" "-" "/css/bootstrap.min.css" "172.17.0.2" "172.17.0.2" "+" "448" "180" "-" "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36" "http://172.17.0.2/" "%" "172.17.42.1" "172.17.42.1" "172.17.0.2" "0" "-" "373" "/usr/share/httpd/noindex/css/open-sans.css" "172.17.42.1" "HTTP/1.1" "0" "-" "-" "GET" "80" "80" "80" "43418" "127" "127" "140597540726848" "140597540726848" "" "GET /css/open-sans.css HTTP/1.1" "-" "304" "304" "[21/Nov/2014:15:48:21 +0000]" "1416584901087" "1416584901087" "1416584901087" "1416584901087430" "1416584901087430" "1416584901087803" "087" "087" "087" "087430" "087430" "087803" "0" "-" "/css/open-sans.css" "172.17.0.2" "172.17.0.2" "+" "444" "181" "-" "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36" "http://172.17.0.2/" "%" "172.17.42.1" "172.17.42.1" "172.17.0.2" "0" "-" "381" "/usr/share/httpd/noindex/images/apache_pb.gif" "172.17.42.1" "HTTP/1.1" "0" "-" "-" "GET" "80" "80" "80" "43419" "128" "128" "140597540726848" "140597540726848" "" "GET /images/apache_pb.gif HTTP/1.1" "-" "304" "304" "[21/Nov/2014:15:48:21 +0000]" "1416584901087" "1416584901087" "1416584901087" "1416584901087445" "1416584901087445" "1416584901087826" "087" "087" "087" "087445" "087445" "087826" "0" "-" "/images/apache_pb.gif" "172.17.0.2" "172.17.0.2" "+" "448" "180" "-" "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36" "http://172.17.0.2/" "%" "172.17.42.1" "172.17.42.1" "172.17.0.2" "0" "-" "269" "/usr/share/httpd/noindex/images/poweredby.png" "172.17.42.1" "HTTP/1.1" "1" "-" "-" "GET" "80" "80" "80" "43419" "128" "128" "140597540726848" "140597540726848" "" "GET /images/poweredby.png HTTP/1.1" "-" "304" "304" "[21/Nov/2014:15:48:21 +0000]" "1416584901091" "1416584901091" "1416584901091" "1416584901091601" "1416584901091601" "1416584901091870" "091" "091" "091" "091601" "091601" "091870" "0" "-" "/images/poweredby.png" "172.17.0.2" "172.17.0.2" "+" "448" "179" "-" "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36" "http://172.17.0.2/" "%" "172.17.42.1" "172.17.42.1" "172.17.0.2" "213" "213" "448" "/var/www/html/ladkshjfkjasdhf" "172.17.42.1" "HTTP/1.1" "0" "-" "-" "GET" "80" "80" "80" "43482" "136" "136" "140597540726848" "140597540726848" "" "GET /ladkshjfkjasdhf HTTP/1.1" "-" "404" "404" "[21/Nov/2014:15:50:45 +0000]" "1416585045231" "1416585045231" "1416585045231" "1416585045231085" "1416585045231085" "1416585045231533" "231" "231" "231" "231085" "231085" "231533" "0" "-" "/ladkshjfkjasdhf" "172.17.0.2" "172.17.0.2" "+" "356" "429" "-" "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 Safari/537.36" "-" ================================================ FILE: devtools/pom.xml ================================================ 4.0.0 parser-parent nl.basjes.parse 6.0.1-SNAPSHOT nl.basjes.parse.devtools devtools jar Parser - Developer Tools https://github.com/nielsbasjes/logparser org.apache.maven.plugins maven-deploy-plugin true org.jacoco jacoco-maven-plugin true ================================================ FILE: devtools/release.sh ================================================ #!/bin/bash # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2025 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Release procedure. # This uses the maven-release-plugin which has been configured to ONLY modify the local git repo. # ---------------------------------------------------------------------------------------------------- SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" echo "PWD: ${SCRIPTDIR}" cd "${SCRIPTDIR}/.." || ( echo "This should not be possible" ; exit 1 ) # Working directory is now the root of the project # ---------------------------------------------------------------------------------------------------- #https://wiki.archlinux.org/index.php/Color_Bash_Prompt # Reset export Color_Off='\e[0m' # Text Reset # High Intensity export IRed='\e[0;91m' # Red export IYellow='\e[0;93m' # Yellow export IBlue='\e[0;94m' # Blue export IWhite='\e[0;97m' # White # Bold High Intensity export BIRed='\e[1;91m' # Red export BIYellow='\e[1;93m' # Yellow export BIGreen='\e[1;92m' # Green export BIBlue='\e[1;94m' # Blue function info() { echo -e "${Color_Off}${IWhite}[${BIBlue}INFO${IWhite}] ${Color_Off}${1}" } function pass() { echo -e "${Color_Off}${IWhite}[${BIGreen}PASS${IWhite}] ${Color_Off}${1}" } function warn() { echo -e "${Color_Off}${IWhite}[${BIYellow}WARN${IWhite}] ${IYellow}${1}${Color_Off}" } function fail() { echo -e "${Color_Off}${IWhite}[${BIRed}FAIL${IWhite}] ${IRed}${1}${Color_Off}" } function die() { echo -e "${Color_Off}" echo -e "${IWhite}[${BIRed}FAIL${IWhite}] ${IYellow}/========================================================================" echo -e "${IWhite}[${BIRed}FAIL${IWhite}] ${IYellow}| ${BIRed} ---------->>> PROCESS WAS ABORTED <<<---------- ${IYellow}" echo -e "${IWhite}[${BIRed}FAIL${IWhite}] ${IYellow}| ${BIRed} $* ${IYellow}" echo -e "${IWhite}[${BIRed}FAIL${IWhite}] ${IYellow}\\========================================================================" echo -e "${Color_Off}" exit 1 } # ---------------------------------------------------------------------------------------------------- # Pre flight checks ## Ensure all has been committed info "Checking tree status" if [[ -z $(git status -s) ]] then pass "Tree is clean" else git status die "Tree is dirty, must commit everything" fi ## Ensure we have all upstream updates (like patches from Renovate) info "Checking up to date status" git pull gitPullStatus=$? if [ ${gitPullStatus} -ne 0 ]; then fail "We just received changes." exit ${gitPullStatus} else pass "Everything is up to date." fi # ---------------------------------------------------------------------------------------------------- # Forcing a manual gpg signing action to ensure the password is known ( cd /tmp || die "Unable to enter /tmp" echo x > ReleaseProcess-$$.txt gpg --clearsign ReleaseProcess-$$.txt rm ReleaseProcess-$$.txt ReleaseProcess-$$.txt.asc ) info "GPG workaround: Starting" runGpgSignerInBackGround(){ while : ; do date ; echo "test" | gpg --clearsign ; sleep 10s ; done } runGpgSignerInBackGround > /dev/null 2>&1 & GpgSignerPID=$! info "GPG workaround: Running (PID=${GpgSignerPID})" killSigner() { info "GPG workaround: Killing (PID=${GpgSignerPID})" kill ${GpgSignerPID} info "GPG workaround: Killed" } trap killSigner EXIT trap killSigner SIGINT # ---------------------------------------------------------------------------------------------------- ## Prepare the release: Make releasable version and make tag. info "Doing release:prepare" mvn release:prepare -B prepareStatus=$? if [ ${prepareStatus} -ne 0 ]; then fail "Release prepare failed." exit ${prepareStatus} else pass "Release prepare Success." fi # ---------------------------------------------------------------------------------------------------- # Check if build for this tag is reproducible git checkout "$(git describe --abbrev=0)" # ---------------------------------------------------------------------------------------------------- info "Publishing for reproduction check to Local repo" mvn clean install -PpackageForRelease -PskipQuality reproCheckPublishStatus=$? if [ ${reproCheckPublishStatus} -ne 0 ]; then git switch - fail "Publishing for reproduction check failed." exit ${reproCheckPublishStatus} else pass "Publishing for reproduction check Success." fi # ---------------------------------------------------------------------------------------------------- info "Checking build reproducability ... " mvn clean verify artifact:compare reproducibleStatus=$? git switch - if [ ${reproducibleStatus} -ne 0 ]; then fail "Build is NOT reproducible." exit ${reproducibleStatus} else pass "Build is reproducible." fi # ---------------------------------------------------------------------------------------------------- # Actually run the release: Effectively mvn deploy towards Sonatype info "Doing release:perform" mvn release:perform performStatus=$? if [ ${performStatus} -ne 0 ]; then fail "Release perform failed." exit ${performStatus} else pass "Release perform Success." fi # ---------------------------------------------------------------------------------------------------- # # Now check SONATYPE # RELEASEVERSION=$(git describe --abbrev=0| sed 's/^v//') info "Now verify Sonatype to release version ${RELEASEVERSION}" info "Go to https://central.sonatype.com/publishing/deployments" warn "Press any key abort or 'c' to continue and update the website" read -n 1 k <&1 if [[ $k = c ]] ; then pass "Release worked, pushing results" else die "Aborting, nothing was pushed." fi # ---------------------------------------------------------------------------------------------------- warn "Now go and manually push it all" # ---------------------------------------------------------------------------------------------------- echo "git push" echo "git push --tags" # ---------------------------------------------------------------------------------------------------- ================================================ FILE: devtools/src/main/resources/checkstyle/checkstyle.xml ================================================ ================================================ FILE: devtools/src/main/resources/checkstyle/suppressions.xml ================================================ ================================================ FILE: docs/CNAME ================================================ logparser.basjes.nl ================================================ FILE: docs/README.md ================================================ Apache HTTPD & NGINX access log parser ====================================== [![Github actions Build status](https://img.shields.io/github/actions/workflow/status/nielsbasjes/logparser/build.yml?branch=main)](https://github.com/nielsbasjes/logparser/actions) [![Coverage Status](https://img.shields.io/codecov/c/github/nielsbasjes/logparser)](https://app.codecov.io/gh/nielsbasjes/logparser) [![License](https://img.shields.io/:license-apache-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Maven Central](https://img.shields.io/maven-central/v/nl.basjes.parse/parser-parent.svg)](https://search.maven.org/#search%7Cga%7C1%7Cg%3A%22nl.basjes.parse.httpdlog%22) [![If this project has business value for you then don't hesitate to support me with a small donation.](https://img.shields.io/badge/Donations-via%20Paypal-blue.svg)](https://www.paypal.me/nielsbasjes) This is a Logparsing framework intended to make parsing [Apache HTTPD](https://httpd.apache.org/) and [NGINX](https://nginx.org/) access log files much easier. The basic idea is that you should be able to have a parser that you can construct by simply telling it with what configuration options the line was written. These configuration options are the schema of the access loglines. So we are using the LogFormat that wrote the file as the input parameter for the parser that reads the same file. In addition to the config options specified in the Apache HTTPD manual under [Custom Log Formats](https://httpd.apache.org/docs/current/mod/mod_log_config.html) the following are also recognized: * common * combined * combinedio * referer * agent For Nginx the log_format tokens are specified [here](https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format) and [here](https://nginx.org/en/docs/http/ngx_http_core_module.html#variables). *** PLACE HOLDER PAGE *** Donations === If this project has business value for you then don't hesitate to support me with a small donation. [![Donations via PayPal](https://img.shields.io/badge/Donations-via%20Paypal-blue.svg)](https://www.paypal.me/nielsbasjes) License === Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: examples/apache-beam/.gitignore ================================================ tmp ================================================ FILE: examples/apache-beam/pom.xml ================================================ 4.0.0 httpdlog-examples nl.basjes.parse.httpdlog.examples 6.0.1-SNAPSHOT apache-beam Parser - Examples - Apache Beam none nl.basjes.parse.httpdlog httpdlog-parser ${project.version} org.apache.beam beam-sdks-java-core ${beam.version} org.projectlombok lombok ${lombok.version} provided org.apache.avro avro ${avro.version} provided org.apache.beam beam-sdks-java-core ${beam.version} tests test org.apache.beam beam-runners-direct-java ${beam.version} test org.hamcrest hamcrest-all 1.3 test org.jacoco jacoco-maven-plugin org.apache.maven.plugins maven-deploy-plugin true org.apache.avro avro-maven-plugin test-schemas generate-test-sources schema protocol idl-protocol String src/test/avro private ================================================ FILE: examples/apache-beam/src/test/avro/Record.avdl ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ @namespace("nl.basjes.parse.webevents") protocol BeamTestRecord { record Device { long screenWidth ; // "SCREENWIDTH:request.firstline.uri.query.s.width" long screenHeight ; // "SCREENHEIGHT:request.firstline.uri.query.s.height" } record Browser { string useragent ; // "STRING:request.user-agent" } record ISP { string asnNumber ; // ASN:connection.client.host.asn.number string asnOrganization ; // STRING:connection.client.host.asn.organization string ispName ; // STRING:connection.client.host.isp.name string ispOrganization ; // STRING:connection.client.host.isp.organization } record GeoLocation { string continentName; // STRING:connection.client.host.continent.name string continentCode; // STRING:connection.client.host.continent.code string countryName; // STRING:connection.client.host.country.name string countryIso; // STRING:connection.client.host.country.iso string subdivisionName; // STRING:connection.client.host.subdivision.name string subdivisionIso; // STRING:connection.client.host.subdivision.iso string cityName; // STRING:connection.client.host.city.name string postalCode; // STRING:connection.client.host.postal.code double locationLatitude; // STRING:connection.client.host.location.latitude double locationLongitude; // STRING:connection.client.host.location.longitude } record Visitor { string ip; // "IP:connection.client.host" ISP isp; GeoLocation geoLocation; } record Click { long timestamp; // "TIME.EPOCH:request.receive.time.epoch" Device device; Browser browser; Visitor visitor; } } ================================================ FILE: examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam/TestCase.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.beam; import nl.basjes.parse.core.Parser; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import nl.basjes.parse.httpdlog.beam.pojo.MyRecord; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector; // CHECKSTYLE.OFF: LineLength // CHECKSTYLE.OFF: LeftCurly // CHECKSTYLE.OFF: HideUtilityClassConstructor public final class TestCase { private static final String TEST_MMDB_BASE_DIR = "../../GeoIP2-TestData/test-data/"; public static final String ISP_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoIP2-ISP-Test.mmdb"; public static final String CITY_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoIP2-City-Test.mmdb"; public static String getLogFormat() { return "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\""; } public static String getInputLine() { return "2001:980:91c0:1:8d31:a232:25e5:85d - - [05/Sep/2010:11:27:50 +0200] \"GET /b/ss/advbolprod2/1/H.22.1/s73176445413647?AQB=1&pccr=true&vidn=27F07A1B85012045-4000011500517C43&&ndh=1&t=19%2F5%2F2012%2023%3A51%3A27%202%20-120&ce=UTF-8&ns=bol&pageName=%2Fnl%2Fp%2Ffissler-speciaal-pannen-grillpan-28-x-28-cm%2F9200000002876066%2F&g=http%3A%2F%2Fwww.bol.com%2Fnl%2Fp%2Ffissler-speciaal-pannen-grillpan-28-x-28-cm%2F9200000002876066%2F%3Fpromo%3Dkoken-pannen_303_hs-koken-pannen-afj-120601_B3_product_1_9200000002876066%26bltg.pg_nm%3Dkoken-pannen%26bltg.slt_id%3D303%26bltg.slt_nm%3Dhs-koken-pannen-afj-120601%26bltg.slt_p&r=http%3A%2F%2Fwww.bol.com%2Fnl%2Fm%2Fkoken-tafelen%2Fkoken-pannen%2FN%2F11766%2Findex.html%3Fblabla%3Dblablawashere&cc=EUR&ch=D%3Dv3&server=ps316&events=prodView%2Cevent1%2Cevent2%2Cevent31&products=%3B9200000002876066%3B%3B%3B%3Bevar3%3Dkth%7Cevar8%3D9200000002876066_Fissler%20Speciaal%20Pannen%20-%20Grillpan%20-%2028%20x%2028%20cm%7Cevar35%3D170%7Cevar47%3DKTH%7Cevar9%3DNew%7Cevar40%3Dno%20reviews%2C%3B%3B%3B%3Bevent31%3D423&c1=catalog%3Akth%3Aproduct-detail&v1=D%3Dc1&h1=catalog%2Fkth%2Fproduct-detail&h2=D%3DpageName&v3=kth&l3=endeca_001-mensen_default%2Cendeca_exact-boeken_default%2Cendeca_verschijningsjaar_default%2Cendeca_hardgoodscategoriesyn_default%2Cendeca_searchrank-hadoop_default%2Cendeca_genre_default%2Cendeca_uitvoering_default&v4=ps316&v6=koken-pannen_303_hs-koken-pannen-afj-120601_B3_product_1_9200000002876066&v10=Tu%2023%3A30&v12=logged%20in&v13=New&c25=niet%20ssl&c26=3631&c30=84.106.227.113.1323208998208762&v31=2000285551&c45=20120619235127&c46=20120501%204.3.4.1&c47=D%3Ds_vi&c49=%2Fnl%2Fcatalog%2Fproduct-detail.jsp&c50=%2Fnl%2Fcatalog%2Fproduct-detail.jsp&v51=www.bol.com&s=1280x800&c=24&j=1.7&v=N&k=Y&bw=1280&bh=272&p=Shockwave%20Flash%3B&AQE=1 HTTP/1.1\" 200 23617 \"http://www.google.nl/imgres?imgurl=http://daniel_en_sander.basjes.nl/fotos/geboorte-kaartje/geboortekaartje-binnenkant.jpg&imgrefurl=http://daniel_en_sander.basjes.nl/fotos/geboorte-kaartje&usg=__LDxRMkacRs6yLluLcIrwoFsXY6o=&h=521&w=1024&sz=41&hl=nl&start=13&zoom=1&um=1&itbs=1&tbnid=Sqml3uGbjoyBYM:&tbnh=76&tbnw=150&prev=/images%3Fq%3Dbinnenkant%2Bgeboortekaartje%26um%3D1%26hl%3Dnl%26sa%3DN%26biw%3D1882%26bih%3D1014%26tbs%3Disch:1\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; nl-nl) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8\" \"jquery-ui-theme=Eggplant; BuI=SomeThing; Apache=127.0.0.1.1351111543699529\""; } public static Parser createTestParser() throws NoSuchMethodException { Parser parser = new HttpdLoglineParser<>(MyRecord.class, getLogFormat()); parser.addDissector(new nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector()); parser.addTypeRemapping("request.firstline.uri.query.g", "HTTP.URI"); parser.addTypeRemapping("request.firstline.uri.query.r", "HTTP.URI"); parser.addTypeRemapping("request.firstline.uri.query.s", "SCREENRESOLUTION"); parser.addParseTarget("setConnectionClientHost", "IP:connection.client.host"); parser.addParseTarget("setRequestReceiveTime", "TIME.STAMP:request.receive.time"); parser.addParseTarget("setReferrer", "STRING:request.firstline.uri.query.g.query.promo"); parser.addParseTarget("setScreenResolution", "STRING:request.firstline.uri.query.s"); parser.addParseTarget("setScreenWidth", "SCREENWIDTH:request.firstline.uri.query.s.width"); parser.addParseTarget("setScreenHeight", "SCREENHEIGHT:request.firstline.uri.query.s.height"); parser.addParseTarget("setGoogleQuery", "STRING:request.firstline.uri.query.r.query.blabla"); parser.addParseTarget("setBui", "HTTP.COOKIE:request.cookies.bui"); parser.addParseTarget("setUseragent", "HTTP.USERAGENT:request.user-agent"); parser.addDissector(new GeoIPISPDissector(ISP_TEST_MMDB)); parser.addParseTarget("setAsnNumber", "ASN:connection.client.host.asn.number"); parser.addParseTarget("setAsnOrganization", "STRING:connection.client.host.asn.organization"); parser.addParseTarget("setIspName", "STRING:connection.client.host.isp.name"); parser.addParseTarget("setIspOrganization", "STRING:connection.client.host.isp.organization"); parser.addDissector(new GeoIPCityDissector(CITY_TEST_MMDB)); parser.addParseTarget("setContinentName", "STRING:connection.client.host.continent.name"); parser.addParseTarget("setContinentCode", "STRING:connection.client.host.continent.code"); parser.addParseTarget("setCountryName", "STRING:connection.client.host.country.name"); parser.addParseTarget("setCountryIso", "STRING:connection.client.host.country.iso"); parser.addParseTarget("setSubdivisionName", "STRING:connection.client.host.subdivision.name"); parser.addParseTarget("setSubdivisionIso", "STRING:connection.client.host.subdivision.iso"); parser.addParseTarget("setCityName", "STRING:connection.client.host.city.name"); parser.addParseTarget("setPostalCode", "STRING:connection.client.host.postal.code"); parser.addParseTarget("setLocationLatitude", "STRING:connection.client.host.location.latitude"); parser.addParseTarget("setLocationLongitude", "STRING:connection.client.host.location.longitude"); return parser; } public static String getExpectedConnectionClientHost() { return "2001:980:91c0:1:8d31:a232:25e5:85d"; } public static String getExpectedRequestReceiveTime() { return "05/Sep/2010:11:27:50 +0200"; } public static Long getExpectedRequestReceiveTimeEpoch() { return 1283678870000L; } public static String getExpectedReferrer() { return "koken-pannen_303_hs-koken-pannen-afj-120601_B3_product_1_9200000002876066"; } public static String getExpectedScreenResolution() { return "1280x800"; } public static Long getExpectedScreenWidth() { return 1280L; } public static Long getExpectedScreenHeight() { return 800L; } public static String getExpectedGoogleQuery() { return "blablawashere"; } public static String getExpectedBui() { return "SomeThing"; } public static String getExpectedUseragent() { return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; nl-nl) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8"; } public static String getExpectedAsnNumber() { return "6666"; } public static String getExpectedAsnOrganization() { return "Basjes Global Network IPv6"; } public static String getExpectedIspName() { return "Basjes ISP IPv6"; } public static String getExpectedIspOrganization() { return "Niels Basjes IPv6"; } public static String getExpectedContinentName() { return "Europe"; } public static String getExpectedContinentCode() { return "EU"; } public static String getExpectedCountryName() { return "Netherlands"; } public static String getExpectedCountryIso() { return "NL"; } public static String getExpectedSubdivisionName() { return "Noord Holland"; } public static String getExpectedSubdivisionIso() { return "NH"; } public static String getExpectedCityName() { return "Amstelveen"; } public static String getExpectedPostalCode() { return "1187"; } public static Double getExpectedLocationLatitude() { return 52.5; } public static Double getExpectedLocationLongitude() { return 5.75; } } ================================================ FILE: examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam/avro/ExpectedClick.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.beam.avro; import nl.basjes.parse.webevents.Click; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedAsnNumber; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedAsnOrganization; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedCityName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedConnectionClientHost; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedContinentCode; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedContinentName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedCountryIso; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedCountryName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedIspName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedIspOrganization; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedLocationLatitude; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedLocationLongitude; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedPostalCode; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedRequestReceiveTimeEpoch; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedScreenHeight; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedScreenWidth; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedSubdivisionIso; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedSubdivisionName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedUseragent; // CHECKSTYLE.OFF: HideUtilityClassConstructor public class ExpectedClick { public static Click create(){ Click.Builder builder = Click.newBuilder(); builder .setTimestamp(getExpectedRequestReceiveTimeEpoch()) .getDeviceBuilder() .setScreenWidth(getExpectedScreenWidth()) .setScreenHeight(getExpectedScreenHeight()); builder .getBrowserBuilder() .setUseragent(getExpectedUseragent()); builder .getVisitorBuilder() .setIp(getExpectedConnectionClientHost()); builder .getVisitorBuilder() .getIspBuilder() .setAsnNumber(getExpectedAsnNumber()) .setAsnOrganization(getExpectedAsnOrganization()) .setIspName(getExpectedIspName()) .setIspOrganization(getExpectedIspOrganization()); builder .getVisitorBuilder() .getGeoLocationBuilder() .setContinentName(getExpectedContinentName()) .setContinentCode(getExpectedContinentCode()) .setCountryName(getExpectedCountryName()) .setCountryIso(getExpectedCountryIso()) .setSubdivisionName(getExpectedSubdivisionName()) .setSubdivisionIso(getExpectedSubdivisionIso()) .setCityName(getExpectedCityName()) .setPostalCode(getExpectedPostalCode()) .setLocationLatitude(getExpectedLocationLatitude()) .setLocationLongitude(getExpectedLocationLongitude()); return builder.build(); } } ================================================ FILE: examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam/avro/TestParserDoFnAvro.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.beam.avro; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import nl.basjes.parse.httpdlog.beam.TestCase; import nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector; import nl.basjes.parse.webevents.Click; import org.apache.beam.sdk.coders.StringUtf8Coder; import org.apache.beam.sdk.testing.PAssert; import org.apache.beam.sdk.testing.TestPipeline; import org.apache.beam.sdk.transforms.Create; import org.apache.beam.sdk.transforms.DoFn; import org.apache.beam.sdk.transforms.ParDo; import org.apache.beam.sdk.values.PCollection; import org.apache.commons.lang3.builder.Builder; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.Serializable; import java.util.Collections; import java.util.List; import static nl.basjes.parse.httpdlog.beam.TestCase.CITY_TEST_MMDB; import static nl.basjes.parse.httpdlog.beam.TestCase.ISP_TEST_MMDB; // CHECKSTYLE.OFF: LineLength // CHECKSTYLE.OFF: LeftCurly @RunWith(JUnit4.class) public class TestParserDoFnAvro implements Serializable { public static class ClickSetter implements Builder { final Click.Builder builder = Click.newBuilder(); @Field("TIME.EPOCH:request.receive.time.epoch") public void setRequestReceiveTime(Long value) { builder.setTimestamp(value); } @Field("SCREENWIDTH:request.firstline.uri.query.s.width") public void setScreenWidth(Long value) { builder.getDeviceBuilder().setScreenWidth(value); } @Field("SCREENHEIGHT:request.firstline.uri.query.s.height") public void setScreenHeight(Long value) { builder.getDeviceBuilder().setScreenHeight(value); } @Field("HTTP.USERAGENT:request.user-agent") public void setUseragent(String value) { builder.getBrowserBuilder().setUseragent(value); } @Field("IP:connection.client.host") public void setConnectionClientHost(String value) { builder.getVisitorBuilder().setIp(value); } @Field("ASN:connection.client.host.asn.number") public void setAsnNumber(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnNumber(value); } @Field("STRING:connection.client.host.asn.organization") public void setAsnOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnOrganization(value); } @Field("STRING:connection.client.host.isp.name") public void setIspName(String value) { builder.getVisitorBuilder().getIspBuilder().setIspName(value); } @Field("STRING:connection.client.host.isp.organization") public void setIspOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setIspOrganization(value); } @Field("STRING:connection.client.host.continent.name") public void setContinentName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentName(value); } @Field("STRING:connection.client.host.continent.code") public void setContinentCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentCode(value); } @Field("STRING:connection.client.host.country.name") public void setCountryName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryName(value); } @Field("STRING:connection.client.host.country.iso") public void setCountryIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryIso(value); } @Field("STRING:connection.client.host.subdivision.name") public void setSubdivisionName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionName(value); } @Field("STRING:connection.client.host.subdivision.iso") public void setSubdivisionIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionIso(value); } @Field("STRING:connection.client.host.city.name") public void setCityName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCityName(value); } @Field("STRING:connection.client.host.postal.code") public void setPostalCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setPostalCode(value); } @Field("STRING:connection.client.host.location.latitude") public void setLocationLatitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLatitude(value); } @Field("STRING:connection.client.host.location.longitude") public void setLocationLongitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLongitude(value); } @Override public Click build() { return builder.build(); } } public static class MyParserDoFn extends DoFn { private Parser parser; @Setup public void setup() { parser = new HttpdLoglineParser<>(ClickSetter.class, TestCase.getLogFormat()) .addDissector(new ScreenResolutionDissector()) .addTypeRemapping("request.firstline.uri.query.g", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.r", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.s", "SCREENRESOLUTION") .addDissector(new GeoIPISPDissector(ISP_TEST_MMDB)) .addDissector(new GeoIPCityDissector(CITY_TEST_MMDB)); } @ProcessElement public void processElement(ProcessContext c) throws InvalidDissectorException, MissingDissectorsException, DissectionFailure { String input = c.element(); ClickSetter setter = parser.parse(new ClickSetter(), input); if (setter == null) { System.err.println("Something went terribly wrong"); return; } Click click = setter.build(); c.output(click); } } @Rule public final transient TestPipeline pipeline = TestPipeline.create(); @Test public void testClassDefinitionAvro() { List logLines = Collections.singletonList(TestCase.getInputLine()); // Apply Create, passing the list and the coder, to create the PCollection. PCollection input = pipeline.apply(Create.of(logLines)).setCoder(StringUtf8Coder.of()); PCollection filledTestRecords = input .apply("Extract Elements from logline", ParDo.of(new MyParserDoFn())); PAssert.that(filledTestRecords).containsInAnyOrder(ExpectedClick.create()); pipeline.run().waitUntilFinish(); } } ================================================ FILE: examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam/avro/TestParserDoFnAvroInline.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.beam.avro; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import nl.basjes.parse.httpdlog.beam.TestCase; import nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector; import nl.basjes.parse.webevents.Click; import org.apache.beam.sdk.coders.StringUtf8Coder; import org.apache.beam.sdk.testing.PAssert; import org.apache.beam.sdk.testing.TestPipeline; import org.apache.beam.sdk.transforms.Create; import org.apache.beam.sdk.transforms.DoFn; import org.apache.beam.sdk.transforms.ParDo; import org.apache.beam.sdk.values.PCollection; import org.apache.commons.lang3.builder.Builder; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.Serializable; import java.util.Collections; import java.util.List; import static nl.basjes.parse.httpdlog.beam.TestCase.CITY_TEST_MMDB; import static nl.basjes.parse.httpdlog.beam.TestCase.ISP_TEST_MMDB; // CHECKSTYLE.OFF: LineLength // CHECKSTYLE.OFF: LeftCurly @RunWith(JUnit4.class) public class TestParserDoFnAvroInline implements Serializable { public static class ClickSetter implements Builder { final Click.Builder builder = Click.newBuilder(); @Field("TIME.EPOCH:request.receive.time.epoch") public void setRequestReceiveTime(Long value) { builder.setTimestamp(value); } @Field("SCREENWIDTH:request.firstline.uri.query.s.width") public void setScreenWidth(Long value) { builder.getDeviceBuilder().setScreenWidth(value); } @Field("SCREENHEIGHT:request.firstline.uri.query.s.height") public void setScreenHeight(Long value) { builder.getDeviceBuilder().setScreenHeight(value); } @Field("HTTP.USERAGENT:request.user-agent") public void setUseragent(String value) { builder.getBrowserBuilder().setUseragent(value); } @Field("IP:connection.client.host") public void setConnectionClientHost(String value) { builder.getVisitorBuilder().setIp(value); } @Field("ASN:connection.client.host.asn.number") public void setAsnNumber(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnNumber(value); } @Field("STRING:connection.client.host.asn.organization") public void setAsnOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnOrganization(value); } @Field("STRING:connection.client.host.isp.name") public void setIspName(String value) { builder.getVisitorBuilder().getIspBuilder().setIspName(value); } @Field("STRING:connection.client.host.isp.organization") public void setIspOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setIspOrganization(value); } @Field("STRING:connection.client.host.continent.name") public void setContinentName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentName(value); } @Field("STRING:connection.client.host.continent.code") public void setContinentCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentCode(value); } @Field("STRING:connection.client.host.country.name") public void setCountryName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryName(value); } @Field("STRING:connection.client.host.country.iso") public void setCountryIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryIso(value); } @Field("STRING:connection.client.host.subdivision.name") public void setSubdivisionName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionName(value); } @Field("STRING:connection.client.host.subdivision.iso") public void setSubdivisionIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionIso(value); } @Field("STRING:connection.client.host.city.name") public void setCityName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCityName(value); } @Field("STRING:connection.client.host.postal.code") public void setPostalCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setPostalCode(value); } @Field("STRING:connection.client.host.location.latitude") public void setLocationLatitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLatitude(value); } @Field("STRING:connection.client.host.location.longitude") public void setLocationLongitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLongitude(value); } @Override public Click build() { return builder.build(); } } @Rule public final transient TestPipeline pipeline = TestPipeline.create(); @Test public void testClassDefinitionAvro() { List logLines = Collections.singletonList(TestCase.getInputLine()); // Apply Create, passing the list and the coder, to create the PCollection. PCollection input = pipeline.apply(Create.of(logLines)).setCoder(StringUtf8Coder.of()); PCollection filledTestRecords = input .apply("Extract Elements from logline", ParDo.of(new DoFn() { private Parser parser; @Setup public void setup() { parser = new HttpdLoglineParser<>(ClickSetter.class, TestCase.getLogFormat()) .addDissector(new ScreenResolutionDissector()) .addTypeRemapping("request.firstline.uri.query.g", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.r", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.s", "SCREENRESOLUTION") .addDissector(new GeoIPISPDissector(ISP_TEST_MMDB)) .addDissector(new GeoIPCityDissector(CITY_TEST_MMDB)); } @ProcessElement public void processElement(ProcessContext c) throws InvalidDissectorException, MissingDissectorsException, DissectionFailure { String input = c.element(); ClickSetter setter = parser.parse(new ClickSetter(), input); Click click = setter.build(); c.output(click); } })); PAssert.that(filledTestRecords).containsInAnyOrder(ExpectedClick.create()); pipeline.run().waitUntilFinish(); } } ================================================ FILE: examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam/pojo/MyRecord.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.beam.pojo; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.junit.Test; import java.io.Serializable; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedAsnNumber; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedAsnOrganization; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedBui; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedCityName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedConnectionClientHost; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedContinentCode; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedContinentName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedCountryIso; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedCountryName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedGoogleQuery; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedIspName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedIspOrganization; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedLocationLatitude; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedLocationLongitude; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedPostalCode; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedReferrer; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedRequestReceiveTime; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedScreenHeight; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedScreenResolution; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedScreenWidth; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedSubdivisionIso; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedSubdivisionName; import static nl.basjes.parse.httpdlog.beam.TestCase.getExpectedUseragent; import static org.junit.Assert.assertEquals; // CHECKSTYLE.OFF: ParamPad @ToString @EqualsAndHashCode public class MyRecord implements Serializable { @Getter @Setter private String connectionClientHost = null; @Getter @Setter private String requestReceiveTime = null; @Getter @Setter private String referrer = null; @Getter @Setter private String screenResolution = null; @Getter @Setter private Long screenWidth = null; @Getter @Setter private Long screenHeight = null; @Getter @Setter private String googleQuery = null; @Getter @Setter private String bui = null; @Getter @Setter private String useragent = null; @Getter @Setter private String asnNumber = null; @Getter @Setter private String asnOrganization = null; @Getter @Setter private String ispName = null; @Getter @Setter private String ispOrganization = null; @Getter @Setter private String continentName = null; @Getter @Setter private String continentCode = null; @Getter @Setter private String countryName = null; @Getter @Setter private String countryIso = null; @Getter @Setter private String subdivisionName = null; @Getter @Setter private String subdivisionIso = null; @Getter @Setter private String cityName = null; @Getter @Setter private String postalCode = null; @Getter @Setter private Double locationLatitude = null; @Getter @Setter private Double locationLongitude = null; public void assertIsValid() { assertEquals(getExpectedConnectionClientHost(), getConnectionClientHost()); assertEquals(getExpectedRequestReceiveTime(), getRequestReceiveTime()); assertEquals(getExpectedReferrer(), getReferrer()); assertEquals(getExpectedScreenResolution(), getScreenResolution()); assertEquals(getExpectedScreenWidth(), getScreenWidth()); assertEquals(getExpectedScreenHeight(), getScreenHeight()); assertEquals(getExpectedGoogleQuery(), getGoogleQuery()); assertEquals(getExpectedBui(), getBui()); assertEquals(getExpectedUseragent(), getUseragent()); assertEquals(getExpectedAsnNumber(), getAsnNumber()); assertEquals(getExpectedAsnOrganization(), getAsnOrganization()); assertEquals(getExpectedIspName(), getIspName()); assertEquals(getExpectedIspOrganization(), getIspOrganization()); assertEquals(getExpectedContinentName(), getContinentName()); assertEquals(getExpectedContinentCode(), getContinentCode()); assertEquals(getExpectedSubdivisionName(), getSubdivisionName()); assertEquals(getExpectedSubdivisionIso(), getSubdivisionIso()); assertEquals(getExpectedCountryName(), getCountryName()); assertEquals(getExpectedCountryIso(), getCountryIso()); assertEquals(getExpectedCityName(), getCityName()); assertEquals(getExpectedPostalCode(), getPostalCode()); assertEquals(getExpectedLocationLatitude(), getLocationLatitude()); assertEquals(getExpectedLocationLongitude(), getLocationLongitude()); } public MyRecord setFullValid() { setConnectionClientHost (getExpectedConnectionClientHost()); setRequestReceiveTime (getExpectedRequestReceiveTime()); setReferrer (getExpectedReferrer()); setScreenResolution (getExpectedScreenResolution()); setScreenWidth (getExpectedScreenWidth()); setScreenHeight (getExpectedScreenHeight()); setGoogleQuery (getExpectedGoogleQuery()); setBui (getExpectedBui()); setUseragent (getExpectedUseragent()); setAsnNumber (getExpectedAsnNumber()); setAsnOrganization (getExpectedAsnOrganization()); setIspName (getExpectedIspName()); setIspOrganization (getExpectedIspOrganization()); setContinentName (getExpectedContinentName()); setContinentCode (getExpectedContinentCode()); setCountryName (getExpectedCountryName()); setCountryIso (getExpectedCountryIso()); setSubdivisionName (getExpectedSubdivisionName()); setSubdivisionIso (getExpectedSubdivisionIso()); setCityName (getExpectedCityName()); setPostalCode (getExpectedPostalCode()); setLocationLatitude (getExpectedLocationLatitude()); setLocationLongitude (getExpectedLocationLongitude()); return this; } @Test public void checkTestMethodsPass() { MyRecord testRecord = new MyRecord().setFullValid(); testRecord.assertIsValid(); } @Test(expected = AssertionError.class) public void checkTestMethodsFail() { MyRecord testRecord = new MyRecord(); testRecord.assertIsValid(); } } ================================================ FILE: examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam/pojo/TestParserDoFnClass.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.beam.pojo; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.httpdlog.beam.TestCase; import org.apache.beam.sdk.coders.StringUtf8Coder; import org.apache.beam.sdk.testing.PAssert; import org.apache.beam.sdk.testing.TestPipeline; import org.apache.beam.sdk.transforms.Create; import org.apache.beam.sdk.transforms.DoFn; import org.apache.beam.sdk.transforms.ParDo; import org.apache.beam.sdk.values.PCollection; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.Serializable; import java.util.Collections; import java.util.List; @RunWith(JUnit4.class) public class TestParserDoFnClass implements Serializable { public static class MyParserDoFn extends DoFn { private final Parser parser; public MyParserDoFn() throws NoSuchMethodException { super(); parser = TestCase.createTestParser(); } @ProcessElement public void processElement(ProcessContext c) throws InvalidDissectorException, MissingDissectorsException, DissectionFailure { c.output(parser.parse(c.element())); } } @Rule public final transient TestPipeline pipeline = TestPipeline.create(); @Test public void testClassDefinition() throws Exception { List logLines = Collections.singletonList(TestCase.getInputLine()); // Apply Create, passing the list and the coder, to create the PCollection. PCollection input = pipeline.apply(Create.of(logLines)).setCoder(StringUtf8Coder.of()); PCollection filledTestRecords = input .apply("Extract Elements from logline", ParDo.of(new MyParserDoFn())); MyRecord expected = new MyRecord().setFullValid(); PAssert.that(filledTestRecords).containsInAnyOrder(expected); pipeline.run().waitUntilFinish(); } } ================================================ FILE: examples/apache-beam/src/test/java/nl/basjes/parse/httpdlog/beam/pojo/TestParserDoFnInline.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.beam.pojo; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.httpdlog.beam.TestCase; import org.apache.beam.sdk.coders.StringUtf8Coder; import org.apache.beam.sdk.testing.PAssert; import org.apache.beam.sdk.testing.TestPipeline; import org.apache.beam.sdk.transforms.Create; import org.apache.beam.sdk.transforms.DoFn; import org.apache.beam.sdk.transforms.ParDo; import org.apache.beam.sdk.values.PCollection; import org.junit.Rule; import org.junit.Test; import java.io.Serializable; import java.util.Collections; import java.util.List; public class TestParserDoFnInline implements Serializable { @Rule public final transient TestPipeline pipeline = TestPipeline.create(); @Test public void testInlineDefinition() { List logLines = Collections.singletonList(TestCase.getInputLine()); // Apply Create, passing the list and the coder, to create the PCollection. PCollection input = pipeline.apply(Create.of(logLines)).setCoder(StringUtf8Coder.of()); PCollection filledTestRecords = input .apply("Extract Elements from logline", ParDo.of(new DoFn() { private Parser parser; @Setup public void setup() throws NoSuchMethodException { parser = TestCase.createTestParser(); } @ProcessElement public void processElement(ProcessContext c) throws InvalidDissectorException, MissingDissectorsException, DissectionFailure { c.output(parser.parse(c.element())); } })); MyRecord expected = new MyRecord().setFullValid(); PAssert.that(filledTestRecords).containsInAnyOrder(expected); pipeline.run().waitUntilFinish(); } } ================================================ FILE: examples/apache-beam/src/test/resources/log4j.properties ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Root logger option log4j.rootLogger=DEBUG, stdout #, file log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.threshold=INFO log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n ## file appender #log4j.appender.file=org.apache.log4j.RollingFileAppender #log4j.appender.file.File=target/debug.log #log4j.appender.file.threshold=DEBUG #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n #log4j.appender.file.Append=false ================================================ FILE: examples/apache-flink/.gitignore ================================================ tmp ================================================ FILE: examples/apache-flink/pom.xml ================================================ 4.0.0 httpdlog-examples nl.basjes.parse.httpdlog.examples 6.0.1-SNAPSHOT apache-flink Parser - Examples - Apache Flink nl.basjes.parse.httpdlog httpdlog-parser ${project.version} org.projectlombok lombok ${lombok.version} provided org.apache.avro avro ${avro.version} provided org.apache.flink flink-avro ${flink.version} provided org.apache.avro avro org.slf4j slf4j-api org.apache.flink flink-core ${flink.version} provided org.slf4j slf4j-api org.apache.commons commons-lang3 commons-collections commons-collections org.apache.flink flink-clients ${flink.version} test org.slf4j slf4j-api org.apache.commons commons-lang3 org.jacoco jacoco-maven-plugin org.apache.maven.plugins maven-deploy-plugin true org.apache.avro avro-maven-plugin test-schemas generate-test-sources schema protocol idl-protocol String src/test/avro private ================================================ FILE: examples/apache-flink/src/test/avro/Record.avdl ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ @namespace("nl.basjes.parse.webevents") protocol FlinkTestRecord { record Device { long screenWidth ; // "SCREENWIDTH:request.firstline.uri.query.s.width" long screenHeight ; // "SCREENHEIGHT:request.firstline.uri.query.s.height" } record Browser { string useragent ; // "STRING:request.user-agent" } record ISP { string asnNumber ; // ASN:connection.client.host.asn.number string asnOrganization ; // STRING:connection.client.host.asn.organization string ispName ; // STRING:connection.client.host.isp.name string ispOrganization ; // STRING:connection.client.host.isp.organization } record GeoLocation { string continentName; // STRING:connection.client.host.continent.name string continentCode; // STRING:connection.client.host.continent.code string countryName; // STRING:connection.client.host.country.name string countryIso; // STRING:connection.client.host.country.iso string subdivisionName; // STRING:connection.client.host.subdivision.name string subdivisionIso; // STRING:connection.client.host.subdivision.iso string cityName; // STRING:connection.client.host.city.name string postalCode; // STRING:connection.client.host.postal.code double locationLatitude; // STRING:connection.client.host.location.latitude double locationLongitude; // STRING:connection.client.host.location.longitude } record Visitor { string ip; // "IP:connection.client.host" ISP isp; GeoLocation geoLocation; } record Click { long timestamp; // "TIME.EPOCH:request.receive.time.epoch" Device device; Browser browser; Visitor visitor; } } ================================================ FILE: examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink/TestCase.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.flink; import nl.basjes.parse.core.Parser; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector; import nl.basjes.parse.httpdlog.flink.pojo.MyRecord; // CHECKSTYLE.OFF: LineLength // CHECKSTYLE.OFF: LeftCurly // CHECKSTYLE.OFF: ParamPad // CHECKSTYLE.OFF: HideUtilityClassConstructor public final class TestCase { private static final String TEST_MMDB_BASE_DIR = "../../GeoIP2-TestData/test-data/"; public static final String ISP_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoIP2-ISP-Test.mmdb"; public static final String CITY_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoIP2-City-Test.mmdb"; public static String getLogFormat() { return "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\""; } public static String getInputLine() { return "2001:980:91c0:1:8d31:a232:25e5:85d - - [05/Sep/2010:11:27:50 +0200] \"GET /b/ss/advbolprod2/1/H.22.1/s73176445413647?AQB=1&pccr=true&vidn=27F07A1B85012045-4000011500517C43&&ndh=1&t=19%2F5%2F2012%2023%3A51%3A27%202%20-120&ce=UTF-8&ns=bol&pageName=%2Fnl%2Fp%2Ffissler-speciaal-pannen-grillpan-28-x-28-cm%2F9200000002876066%2F&g=http%3A%2F%2Fwww.bol.com%2Fnl%2Fp%2Ffissler-speciaal-pannen-grillpan-28-x-28-cm%2F9200000002876066%2F%3Fpromo%3Dkoken-pannen_303_hs-koken-pannen-afj-120601_B3_product_1_9200000002876066%26bltg.pg_nm%3Dkoken-pannen%26bltg.slt_id%3D303%26bltg.slt_nm%3Dhs-koken-pannen-afj-120601%26bltg.slt_p&r=http%3A%2F%2Fwww.bol.com%2Fnl%2Fm%2Fkoken-tafelen%2Fkoken-pannen%2FN%2F11766%2Findex.html%3Fblabla%3Dblablawashere&cc=EUR&ch=D%3Dv3&server=ps316&events=prodView%2Cevent1%2Cevent2%2Cevent31&products=%3B9200000002876066%3B%3B%3B%3Bevar3%3Dkth%7Cevar8%3D9200000002876066_Fissler%20Speciaal%20Pannen%20-%20Grillpan%20-%2028%20x%2028%20cm%7Cevar35%3D170%7Cevar47%3DKTH%7Cevar9%3DNew%7Cevar40%3Dno%20reviews%2C%3B%3B%3B%3Bevent31%3D423&c1=catalog%3Akth%3Aproduct-detail&v1=D%3Dc1&h1=catalog%2Fkth%2Fproduct-detail&h2=D%3DpageName&v3=kth&l3=endeca_001-mensen_default%2Cendeca_exact-boeken_default%2Cendeca_verschijningsjaar_default%2Cendeca_hardgoodscategoriesyn_default%2Cendeca_searchrank-hadoop_default%2Cendeca_genre_default%2Cendeca_uitvoering_default&v4=ps316&v6=koken-pannen_303_hs-koken-pannen-afj-120601_B3_product_1_9200000002876066&v10=Tu%2023%3A30&v12=logged%20in&v13=New&c25=niet%20ssl&c26=3631&c30=84.106.227.113.1323208998208762&v31=2000285551&c45=20120619235127&c46=20120501%204.3.4.1&c47=D%3Ds_vi&c49=%2Fnl%2Fcatalog%2Fproduct-detail.jsp&c50=%2Fnl%2Fcatalog%2Fproduct-detail.jsp&v51=www.bol.com&s=1280x800&c=24&j=1.7&v=N&k=Y&bw=1280&bh=272&p=Shockwave%20Flash%3B&AQE=1 HTTP/1.1\" 200 23617 \"http://www.google.nl/imgres?imgurl=http://daniel_en_sander.basjes.nl/fotos/geboorte-kaartje/geboortekaartje-binnenkant.jpg&imgrefurl=http://daniel_en_sander.basjes.nl/fotos/geboorte-kaartje&usg=__LDxRMkacRs6yLluLcIrwoFsXY6o=&h=521&w=1024&sz=41&hl=nl&start=13&zoom=1&um=1&itbs=1&tbnid=Sqml3uGbjoyBYM:&tbnh=76&tbnw=150&prev=/images%3Fq%3Dbinnenkant%2Bgeboortekaartje%26um%3D1%26hl%3Dnl%26sa%3DN%26biw%3D1882%26bih%3D1014%26tbs%3Disch:1\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; nl-nl) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8\" \"jquery-ui-theme=Eggplant; BuI=SomeThing; Apache=127.0.0.1.1351111543699529\""; } public static Parser createTestParser() throws NoSuchMethodException { Parser parser = new HttpdLoglineParser<>(MyRecord.class, getLogFormat()); parser.addDissector(new nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector()); parser.addTypeRemapping("request.firstline.uri.query.g", "HTTP.URI"); parser.addTypeRemapping("request.firstline.uri.query.r", "HTTP.URI"); parser.addTypeRemapping("request.firstline.uri.query.s", "SCREENRESOLUTION"); parser.addParseTarget("setConnectionClientHost", "IP:connection.client.host"); parser.addParseTarget("setRequestReceiveTime", "TIME.STAMP:request.receive.time"); parser.addParseTarget("setReferrer", "STRING:request.firstline.uri.query.g.query.promo"); parser.addParseTarget("setScreenResolution", "STRING:request.firstline.uri.query.s"); parser.addParseTarget("setScreenWidth", "SCREENWIDTH:request.firstline.uri.query.s.width"); parser.addParseTarget("setScreenHeight", "SCREENHEIGHT:request.firstline.uri.query.s.height"); parser.addParseTarget("setGoogleQuery", "STRING:request.firstline.uri.query.r.query.blabla"); parser.addParseTarget("setBui", "HTTP.COOKIE:request.cookies.bui"); parser.addParseTarget("setUseragent", "HTTP.USERAGENT:request.user-agent"); parser.addDissector(new GeoIPISPDissector(ISP_TEST_MMDB)); parser.addParseTarget("setAsnNumber", "ASN:connection.client.host.asn.number"); parser.addParseTarget("setAsnOrganization", "STRING:connection.client.host.asn.organization"); parser.addParseTarget("setIspName", "STRING:connection.client.host.isp.name"); parser.addParseTarget("setIspOrganization", "STRING:connection.client.host.isp.organization"); parser.addDissector(new GeoIPCityDissector(CITY_TEST_MMDB)); parser.addParseTarget("setContinentName", "STRING:connection.client.host.continent.name"); parser.addParseTarget("setContinentCode", "STRING:connection.client.host.continent.code"); parser.addParseTarget("setCountryName", "STRING:connection.client.host.country.name"); parser.addParseTarget("setCountryIso", "STRING:connection.client.host.country.iso"); parser.addParseTarget("setSubdivisionName", "STRING:connection.client.host.subdivision.name"); parser.addParseTarget("setSubdivisionIso", "STRING:connection.client.host.subdivision.iso"); parser.addParseTarget("setCityName", "STRING:connection.client.host.city.name"); parser.addParseTarget("setPostalCode", "STRING:connection.client.host.postal.code"); parser.addParseTarget("setLocationLatitude", "STRING:connection.client.host.location.latitude"); parser.addParseTarget("setLocationLongitude", "STRING:connection.client.host.location.longitude"); return parser; } public static String getExpectedConnectionClientHost() { return "2001:980:91c0:1:8d31:a232:25e5:85d"; } public static String getExpectedRequestReceiveTime() { return "05/Sep/2010:11:27:50 +0200"; } public static Long getExpectedRequestReceiveTimeEpoch() { return 1283678870000L; } public static String getExpectedReferrer() { return "koken-pannen_303_hs-koken-pannen-afj-120601_B3_product_1_9200000002876066"; } public static String getExpectedScreenResolution() { return "1280x800"; } public static Long getExpectedScreenWidth() { return 1280L; } public static Long getExpectedScreenHeight() { return 800L; } public static String getExpectedGoogleQuery() { return "blablawashere"; } public static String getExpectedBui() { return "SomeThing"; } public static String getExpectedUseragent() { return "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; nl-nl) AppleWebKit/533.17.8 (KHTML, like Gecko) Version/5.0.1 Safari/533.17.8"; } public static String getExpectedAsnNumber() { return "6666"; } public static String getExpectedAsnOrganization() { return "Basjes Global Network IPv6"; } public static String getExpectedIspName() { return "Basjes ISP IPv6"; } public static String getExpectedIspOrganization() { return "Niels Basjes IPv6"; } public static String getExpectedContinentName() { return "Europe"; } public static String getExpectedContinentCode() { return "EU"; } public static String getExpectedCountryName() { return "Netherlands"; } public static String getExpectedCountryIso() { return "NL"; } public static String getExpectedSubdivisionName() { return "Noord Holland"; } public static String getExpectedSubdivisionIso() { return "NH"; } public static String getExpectedCityName() { return "Amstelveen"; } public static String getExpectedPostalCode() { return "1187"; } public static Double getExpectedLocationLatitude() { return 52.5; } public static Double getExpectedLocationLongitude() { return 5.75; } } ================================================ FILE: examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink/avro/ExpectedClick.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.flink.avro; import nl.basjes.parse.webevents.Click; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedAsnNumber; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedAsnOrganization; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedCityName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedConnectionClientHost; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedContinentCode; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedContinentName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedCountryIso; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedCountryName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedIspName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedIspOrganization; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedLocationLatitude; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedLocationLongitude; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedPostalCode; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedRequestReceiveTimeEpoch; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedScreenHeight; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedScreenWidth; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedSubdivisionIso; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedSubdivisionName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedUseragent; // CHECKSTYLE.OFF: HideUtilityClassConstructor public class ExpectedClick { public static Click create(){ Click.Builder builder = Click.newBuilder(); builder .setTimestamp(getExpectedRequestReceiveTimeEpoch()) .getDeviceBuilder() .setScreenWidth(getExpectedScreenWidth()) .setScreenHeight(getExpectedScreenHeight()); builder .getBrowserBuilder() .setUseragent(getExpectedUseragent()); builder .getVisitorBuilder() .setIp(getExpectedConnectionClientHost()); builder .getVisitorBuilder() .getIspBuilder() .setAsnNumber(getExpectedAsnNumber()) .setAsnOrganization(getExpectedAsnOrganization()) .setIspName(getExpectedIspName()) .setIspOrganization(getExpectedIspOrganization()); builder .getVisitorBuilder() .getGeoLocationBuilder() .setContinentName(getExpectedContinentName()) .setContinentCode(getExpectedContinentCode()) .setCountryName(getExpectedCountryName()) .setCountryIso(getExpectedCountryIso()) .setSubdivisionName(getExpectedSubdivisionName()) .setSubdivisionIso(getExpectedSubdivisionIso()) .setCityName(getExpectedCityName()) .setPostalCode(getExpectedPostalCode()) .setLocationLatitude(getExpectedLocationLatitude()) .setLocationLongitude(getExpectedLocationLongitude()); return builder.build(); } } ================================================ FILE: examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink/avro/TestParserMapFunctionAvroClass.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.flink.avro; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector; import nl.basjes.parse.httpdlog.flink.TestCase; import nl.basjes.parse.webevents.Click; import org.apache.commons.lang3.builder.Builder; import org.apache.flink.api.common.functions.OpenContext; import org.apache.flink.api.common.functions.RichMapFunction; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.LocalStreamEnvironment; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.junit.jupiter.api.Test; import java.io.Serializable; import java.util.List; import static nl.basjes.parse.httpdlog.flink.TestCase.CITY_TEST_MMDB; import static nl.basjes.parse.httpdlog.flink.TestCase.ISP_TEST_MMDB; import static org.junit.jupiter.api.Assertions.assertEquals; // CHECKSTYLE.OFF: LineLength // CHECKSTYLE.OFF: LeftCurly class TestParserMapFunctionAvroClass implements Serializable { public static class ClickSetter implements Builder { final Click.Builder builder = Click.newBuilder(); @Field("TIME.EPOCH:request.receive.time.epoch") public void setRequestReceiveTime(Long value) { builder.setTimestamp(value); } @Field("SCREENWIDTH:request.firstline.uri.query.s.width") public void setScreenWidth(Long value) { builder.getDeviceBuilder().setScreenWidth(value); } @Field("SCREENHEIGHT:request.firstline.uri.query.s.height") public void setScreenHeight(Long value) { builder.getDeviceBuilder().setScreenHeight(value); } @Field("HTTP.USERAGENT:request.user-agent") public void setUseragent(String value) { builder.getBrowserBuilder().setUseragent(value); } @Field("IP:connection.client.host") public void setConnectionClientHost(String value) { builder.getVisitorBuilder().setIp(value); } @Field("ASN:connection.client.host.asn.number") public void setAsnNumber(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnNumber(value); } @Field("STRING:connection.client.host.asn.organization") public void setAsnOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnOrganization(value); } @Field("STRING:connection.client.host.isp.name") public void setIspName(String value) { builder.getVisitorBuilder().getIspBuilder().setIspName(value); } @Field("STRING:connection.client.host.isp.organization") public void setIspOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setIspOrganization(value); } @Field("STRING:connection.client.host.continent.name") public void setContinentName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentName(value); } @Field("STRING:connection.client.host.continent.code") public void setContinentCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentCode(value); } @Field("STRING:connection.client.host.country.name") public void setCountryName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryName(value); } @Field("STRING:connection.client.host.country.iso") public void setCountryIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryIso(value); } @Field("STRING:connection.client.host.subdivision.name") public void setSubdivisionName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionName(value); } @Field("STRING:connection.client.host.subdivision.iso") public void setSubdivisionIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionIso(value); } @Field("STRING:connection.client.host.city.name") public void setCityName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCityName(value); } @Field("STRING:connection.client.host.postal.code") public void setPostalCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setPostalCode(value); } @Field("STRING:connection.client.host.location.latitude") public void setLocationLatitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLatitude(value); } @Field("STRING:connection.client.host.location.longitude") public void setLocationLongitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLongitude(value); } @Override public Click build() { return builder.build(); } } public static class MyParserMapper extends RichMapFunction { private Parser parser; @Override public void open(OpenContext openContext) { parser = new HttpdLoglineParser<>(ClickSetter.class, TestCase.getLogFormat()) .addDissector(new ScreenResolutionDissector()) .addTypeRemapping("request.firstline.uri.query.g", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.r", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.s", "SCREENRESOLUTION") .addDissector(new GeoIPISPDissector(ISP_TEST_MMDB)) .addDissector(new GeoIPCityDissector(CITY_TEST_MMDB)); } @Override public Click map(String input) throws Exception { ClickSetter setter = parser.parse(new ClickSetter(), input); if (setter == null) { System.err.println("Something went terribly wrong"); return null; } return setter.build(); } } @Test void testClassDefinitionAvro() throws Exception { // set up the execution environment final StreamExecutionEnvironment env = LocalStreamEnvironment.getExecutionEnvironment(); env.setParallelism(1); DataStream input = env.fromData(TestCase.getInputLine()); DataStream filledTestRecords = input .map(new MyParserMapper()) .name("Extract Elements from logline"); filledTestRecords.print(); List result = filledTestRecords.executeAndCollect(100); assertEquals(1, result.size()); assertEquals(ExpectedClick.create(), result.getFirst()); } } ================================================ FILE: examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink/avro/TestParserMapFunctionAvroInline.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.flink.avro; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector; import nl.basjes.parse.httpdlog.flink.TestCase; import nl.basjes.parse.webevents.Click; import org.apache.commons.lang3.builder.Builder; import org.apache.flink.api.common.functions.OpenContext; import org.apache.flink.api.common.functions.RichMapFunction; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.LocalStreamEnvironment; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.junit.jupiter.api.Test; import java.io.Serializable; import java.util.List; import static nl.basjes.parse.httpdlog.flink.TestCase.CITY_TEST_MMDB; import static nl.basjes.parse.httpdlog.flink.TestCase.ISP_TEST_MMDB; import static org.junit.jupiter.api.Assertions.assertEquals; // CHECKSTYLE.OFF: LineLength // CHECKSTYLE.OFF: LeftCurly class TestParserMapFunctionAvroInline implements Serializable { public static class ClickSetter implements Builder { final Click.Builder builder = Click.newBuilder(); @Field("TIME.EPOCH:request.receive.time.epoch") public void setRequestReceiveTime(Long value) { builder.setTimestamp(value); } @Field("SCREENWIDTH:request.firstline.uri.query.s.width") public void setScreenWidth(Long value) { builder.getDeviceBuilder().setScreenWidth(value); } @Field("SCREENHEIGHT:request.firstline.uri.query.s.height") public void setScreenHeight(Long value) { builder.getDeviceBuilder().setScreenHeight(value); } @Field("HTTP.USERAGENT:request.user-agent") public void setUseragent(String value) { builder.getBrowserBuilder().setUseragent(value); } @Field("IP:connection.client.host") public void setConnectionClientHost(String value) { builder.getVisitorBuilder().setIp(value); } @Field("ASN:connection.client.host.asn.number") public void setAsnNumber(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnNumber(value); } @Field("STRING:connection.client.host.asn.organization") public void setAsnOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setAsnOrganization(value); } @Field("STRING:connection.client.host.isp.name") public void setIspName(String value) { builder.getVisitorBuilder().getIspBuilder().setIspName(value); } @Field("STRING:connection.client.host.isp.organization") public void setIspOrganization(String value) { builder.getVisitorBuilder().getIspBuilder().setIspOrganization(value); } @Field("STRING:connection.client.host.continent.name") public void setContinentName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentName(value); } @Field("STRING:connection.client.host.continent.code") public void setContinentCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setContinentCode(value); } @Field("STRING:connection.client.host.country.name") public void setCountryName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryName(value); } @Field("STRING:connection.client.host.country.iso") public void setCountryIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCountryIso(value); } @Field("STRING:connection.client.host.subdivision.name") public void setSubdivisionName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionName(value); } @Field("STRING:connection.client.host.subdivision.iso") public void setSubdivisionIso(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setSubdivisionIso(value); } @Field("STRING:connection.client.host.city.name") public void setCityName(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setCityName(value); } @Field("STRING:connection.client.host.postal.code") public void setPostalCode(String value) { builder.getVisitorBuilder().getGeoLocationBuilder().setPostalCode(value); } @Field("STRING:connection.client.host.location.latitude") public void setLocationLatitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLatitude(value); } @Field("STRING:connection.client.host.location.longitude") public void setLocationLongitude(Double value) { builder.getVisitorBuilder().getGeoLocationBuilder().setLocationLongitude(value); } @Override public Click build() { return builder.build(); } } @Test void testInlineDefinitionAvro() throws Exception { // set up the execution environment final StreamExecutionEnvironment env = LocalStreamEnvironment.getExecutionEnvironment(); env.setParallelism(1); DataStream input = env.fromData(TestCase.getInputLine()); DataStream filledTestRecords = input .map(new RichMapFunction() { private Parser parser; @Override public void open(OpenContext openContext) { parser = new HttpdLoglineParser<>(ClickSetter.class, TestCase.getLogFormat()) .addDissector(new ScreenResolutionDissector()) .addTypeRemapping("request.firstline.uri.query.g", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.r", "HTTP.URI") .addTypeRemapping("request.firstline.uri.query.s", "SCREENRESOLUTION") .addDissector(new GeoIPISPDissector(ISP_TEST_MMDB)) .addDissector(new GeoIPCityDissector(CITY_TEST_MMDB)); } @Override public Click map(String line) throws Exception { return parser.parse(line).build(); } }).name("Extract Elements from logline"); filledTestRecords.print(); List result = filledTestRecords.executeAndCollect(100); assertEquals(1, result.size()); assertEquals(ExpectedClick.create(), result.getFirst()); } } ================================================ FILE: examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink/pojo/MyRecord.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.flink.pojo; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; import org.junit.jupiter.api.Test; import java.io.Serializable; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedAsnNumber; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedAsnOrganization; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedBui; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedCityName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedConnectionClientHost; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedContinentCode; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedContinentName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedCountryIso; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedCountryName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedGoogleQuery; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedIspName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedIspOrganization; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedLocationLatitude; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedLocationLongitude; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedPostalCode; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedReferrer; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedRequestReceiveTime; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedScreenHeight; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedScreenResolution; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedScreenWidth; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedSubdivisionIso; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedSubdivisionName; import static nl.basjes.parse.httpdlog.flink.TestCase.getExpectedUseragent; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; // CHECKSTYLE.OFF: ParamPad @ToString @EqualsAndHashCode public class MyRecord implements Serializable { @Getter @Setter private String connectionClientHost = null; @Getter @Setter private String requestReceiveTime = null; @Getter @Setter private String referrer = null; @Getter @Setter private String screenResolution = null; @Getter @Setter private Long screenWidth = null; @Getter @Setter private Long screenHeight = null; @Getter @Setter private String googleQuery = null; @Getter @Setter private String bui = null; @Getter @Setter private String useragent = null; @Getter @Setter private String asnNumber = null; @Getter @Setter private String asnOrganization = null; @Getter @Setter private String ispName = null; @Getter @Setter private String ispOrganization = null; @Getter @Setter private String continentName = null; @Getter @Setter private String continentCode = null; @Getter @Setter private String countryName = null; @Getter @Setter private String countryIso = null; @Getter @Setter private String subdivisionName = null; @Getter @Setter private String subdivisionIso = null; @Getter @Setter private String cityName = null; @Getter @Setter private String postalCode = null; @Getter @Setter private Double locationLatitude = null; @Getter @Setter private Double locationLongitude = null; public void assertIsValid() { assertEquals(getExpectedConnectionClientHost(), getConnectionClientHost()); assertEquals(getExpectedRequestReceiveTime(), getRequestReceiveTime()); assertEquals(getExpectedReferrer(), getReferrer()); assertEquals(getExpectedScreenResolution(), getScreenResolution()); assertEquals(getExpectedScreenWidth(), getScreenWidth()); assertEquals(getExpectedScreenHeight(), getScreenHeight()); assertEquals(getExpectedGoogleQuery(), getGoogleQuery()); assertEquals(getExpectedBui(), getBui()); assertEquals(getExpectedUseragent(), getUseragent()); assertEquals(getExpectedAsnNumber(), getAsnNumber()); assertEquals(getExpectedAsnOrganization(), getAsnOrganization()); assertEquals(getExpectedIspName(), getIspName()); assertEquals(getExpectedIspOrganization(), getIspOrganization()); assertEquals(getExpectedContinentName(), getContinentName()); assertEquals(getExpectedContinentCode(), getContinentCode()); assertEquals(getExpectedSubdivisionName(), getSubdivisionName()); assertEquals(getExpectedSubdivisionIso(), getSubdivisionIso()); assertEquals(getExpectedCountryName(), getCountryName()); assertEquals(getExpectedCountryIso(), getCountryIso()); assertEquals(getExpectedCityName(), getCityName()); assertEquals(getExpectedPostalCode(), getPostalCode()); assertEquals(getExpectedLocationLatitude(), getLocationLatitude()); assertEquals(getExpectedLocationLongitude(), getLocationLongitude()); } public MyRecord setFullValid() { setConnectionClientHost (getExpectedConnectionClientHost()); setRequestReceiveTime (getExpectedRequestReceiveTime()); setReferrer (getExpectedReferrer()); setScreenResolution (getExpectedScreenResolution()); setScreenWidth (getExpectedScreenWidth()); setScreenHeight (getExpectedScreenHeight()); setGoogleQuery (getExpectedGoogleQuery()); setBui (getExpectedBui()); setUseragent (getExpectedUseragent()); setAsnNumber (getExpectedAsnNumber()); setAsnOrganization (getExpectedAsnOrganization()); setIspName (getExpectedIspName()); setIspOrganization (getExpectedIspOrganization()); setContinentName (getExpectedContinentName()); setContinentCode (getExpectedContinentCode()); setCountryName (getExpectedCountryName()); setCountryIso (getExpectedCountryIso()); setSubdivisionName (getExpectedSubdivisionName()); setSubdivisionIso (getExpectedSubdivisionIso()); setCityName (getExpectedCityName()); setPostalCode (getExpectedPostalCode()); setLocationLatitude (getExpectedLocationLatitude()); setLocationLongitude (getExpectedLocationLongitude()); return this; } @Test void checkTestMethodsPass() { MyRecord testRecord = new MyRecord().setFullValid(); testRecord.assertIsValid(); } @Test void checkTestMethodsFail() { assertThrows(AssertionError.class, () -> { MyRecord testRecord = new MyRecord(); testRecord.assertIsValid(); }); } } ================================================ FILE: examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink/pojo/TestParserMapFunctionClass.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.flink.pojo; import nl.basjes.parse.core.Parser; import nl.basjes.parse.httpdlog.flink.TestCase; import org.apache.flink.api.common.functions.OpenContext; import org.apache.flink.api.common.functions.RichMapFunction; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.LocalStreamEnvironment; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.junit.jupiter.api.Test; import java.io.Serializable; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; class TestParserMapFunctionClass implements Serializable { public static class MyParserMapper extends RichMapFunction { private Parser parser; @Override public void open(OpenContext openContext) throws Exception { parser = TestCase.createTestParser(); } @Override public MyRecord map(String line) throws Exception { return parser.parse(line); } } @Test void testClassDefinition() throws Exception { // set up the execution environment final StreamExecutionEnvironment env = LocalStreamEnvironment.getExecutionEnvironment(); env.setParallelism(1); DataStream input = env.fromData(TestCase.getInputLine()); DataStream filledTestRecords = input .map(new MyParserMapper()) .name("Extract Elements from logline"); filledTestRecords.print(); List result = filledTestRecords.executeAndCollect(100); assertEquals(1, result.size()); assertEquals(new MyRecord().setFullValid(), result.getFirst()); } } ================================================ FILE: examples/apache-flink/src/test/java/nl/basjes/parse/httpdlog/flink/pojo/TestParserMapFunctionInline.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.flink.pojo; import nl.basjes.parse.core.Parser; import nl.basjes.parse.httpdlog.flink.TestCase; import org.apache.flink.api.common.functions.OpenContext; import org.apache.flink.api.common.functions.RichMapFunction; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.LocalStreamEnvironment; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.junit.jupiter.api.Test; import java.io.Serializable; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; class TestParserMapFunctionInline implements Serializable { @Test void testInlineDefinition() throws Exception { // set up the execution environment final StreamExecutionEnvironment env = LocalStreamEnvironment.getExecutionEnvironment(); env.setParallelism(1); DataStream input = env.fromData(TestCase.getInputLine()); DataStream filledTestRecords = input .map(new RichMapFunction() { private Parser parser; @Override public void open(OpenContext openContext) throws Exception { parser = TestCase.createTestParser(); } @Override public MyRecord map(String line) throws Exception { return parser.parse(line); } }).name("Extract Elements from logline"); filledTestRecords.print(); List result = filledTestRecords.executeAndCollect(100); assertEquals(1, result.size()); assertEquals(new MyRecord().setFullValid(), result.getFirst()); } } ================================================ FILE: examples/apache-flink/src/test/resources/log4j.properties ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Root logger option log4j.rootLogger=DEBUG, stdout #, file log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.threshold=INFO log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n ## file appender #log4j.appender.file=org.apache.log4j.RollingFileAppender #log4j.appender.file.File=target/debug.log #log4j.appender.file.threshold=DEBUG #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n #log4j.appender.file.Append=false ================================================ FILE: examples/apache-hadoop-mapreduce/.gitignore ================================================ debug-output output ================================================ FILE: examples/apache-hadoop-mapreduce/pom.xml ================================================ 4.0.0 httpdlog-examples nl.basjes.parse.httpdlog.examples 6.0.1-SNAPSHOT apache-hadoop-mapreduce Parser - Examples - Apache Hadoop MapReduce UTF-8 nl.basjes.hadoop.io.input.Wordcount none org.apache.hadoop hadoop-client ${hadoop.version} provided org.apache.commons commons-text nl.basjes.parse.httpdlog ${project.version} httpdlog-inputformat org.apache.maven.plugins maven-assembly-plugin make-super-jar package single src/main/assembly/job.xml true ${mainClass} org.apache.maven.plugins maven-deploy-plugin true ================================================ FILE: examples/apache-hadoop-mapreduce/src/main/assembly/job.xml ================================================ job jar false false lib false compile ${project.build.outputDirectory} ${file.separator} ================================================ FILE: examples/apache-hadoop-mapreduce/src/main/java/nl/basjes/hadoop/io/input/Wordcount.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.hadoop.io.input; import nl.basjes.hadoop.input.ApacheHttpdLogfileInputFormat; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configured; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.MapWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.io.Writable; import org.apache.hadoop.mapreduce.Job; import org.apache.hadoop.mapreduce.Mapper; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.mapreduce.lib.reduce.LongSumReducer; import org.apache.hadoop.util.GenericOptionsParser; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; import java.io.IOException; import java.util.List; import java.util.Map; public class Wordcount extends Configured implements Tool { // ---------------------------------------------------------------------- private final String logFormat; public Wordcount(String logFormat) { this.logFormat = logFormat; } // ---------------------------------------------------------------------- public static class TokenizerMapper extends Mapper { private static final LongWritable ONE = new LongWritable(1); private final Text word = new Text(); @Override public void map(Object key, MapWritable value, Context context) throws IOException, InterruptedException { for (Map.Entry entry : value.entrySet()) { word.set(entry.getValue().toString()); context.write(word, ONE); } } } // ---------------------------------------------------------------------- @Override public int run(String[] args) throws Exception { Configuration conf = new Configuration(); String[] otherArgs = new GenericOptionsParser(conf, args) .getRemainingArgs(); if (otherArgs.length != 2) { System.err.println("Usage: wordcount "); return 2; } conf.set("nl.basjes.parse.apachehttpdlogline.format", logFormat); // A ',' separated list of fields conf.set("nl.basjes.parse.apachehttpdlogline.fields", "STRING:request.status.last"); Job job = Job.getInstance(conf, "word count"); job.setJarByClass(Wordcount.class); FileInputFormat.addInputPath(job, new Path(otherArgs[0])); job.setInputFormatClass(ApacheHttpdLogfileInputFormat.class); job.setMapperClass(TokenizerMapper.class); job.setCombinerClass(LongSumReducer.class); job.setReducerClass(LongSumReducer.class); // configuration should contain reference to your namenode FileSystem fs = FileSystem.get(conf); // true stands for recursively deleting the folder you gave Path outputPath = new Path(otherArgs[1]); fs.delete(outputPath, true); FileOutputFormat.setOutputPath(job, outputPath); job.setOutputKeyClass(Text.class); job.setOutputValueClass(LongWritable.class); if (job.waitForCompletion(true)) { return 0; } return 1; } // ---------------------------------------------------------------------- public static void main(String[] args) throws Exception { // httpd.conf has this next line: // LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined String logFormat = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""; // Developer suggestion: // This is what you do to find out what the possible fields are: List possibleFields = ApacheHttpdLogfileInputFormat .listPossibleFields(logFormat, null, null); System.out.println("----------------------------------------"); System.out.println("All possible fields are:"); for (String field : possibleFields) { System.out.println(field); } System.out.println("----------------------------------------"); System.exit(ToolRunner.run(new Configuration(), new Wordcount(logFormat), args)); } // ---------------------------------------------------------------------- } ================================================ FILE: examples/demolog/README.md ================================================ The file hackers-access.log is a sample of the access logs from my home webserver. This file is in the 'combined' LogFormat LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined Although small (3456 lines) this is useful to do testing on parsing and aggregating the data. All of these ips have accessed the /join_form URL. Although it exists this URL is nowhere advertised. So only if you already 'know' this url should exist will a visitor try this. No normal visitor knows this. Not even google knows this. So the only people who 'know' this are hackers trying to break in (and fail in this case). Apache HTTPD & NGINX Access log parsing made easy Copyright (C) 2011-2023 Niels Basjes Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: examples/demolog/hackers-access.log ================================================ 195.154.46.135 - - [25/Oct/2015:04:11:25 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.237.180 - - [25/Oct/2015:04:11:26 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.237.180 - - [25/Oct/2015:04:11:27 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.5.157 - - [25/Oct/2015:04:24:31 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 158.222.5.157 - - [25/Oct/2015:04:24:32 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 158.222.5.157 - - [25/Oct/2015:04:24:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 158.222.5.157 - - [25/Oct/2015:04:24:39 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 158.222.5.157 - - [25/Oct/2015:04:24:41 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 5.39.5.5 - - [25/Oct/2015:04:32:22 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.64.16 - - [25/Oct/2015:04:34:37 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:04:34:40 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:04:34:42 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:04:34:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:04:34:46 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:04:34:51 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.39.5.5 - - [25/Oct/2015:04:37:47 +0100] "GET / HTTP/1.1" 200 17057 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 222.88.236.235 - - [25/Oct/2015:04:39:09 +0100] "GET http://niels.basj.es/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 222.88.236.235 - - [25/Oct/2015:04:39:12 +0100] "GET http://niels.basj.es/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.39.5.5 - - [25/Oct/2015:04:40:46 +0100] "GET / HTTP/1.1" 200 17057 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 89.42.237.71 - - [25/Oct/2015:05:06:41 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 89.42.237.71 - - [25/Oct/2015:05:06:42 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 89.42.237.71 - - [25/Oct/2015:05:06:43 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 89.42.237.71 - - [25/Oct/2015:05:06:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 89.42.237.71 - - [25/Oct/2015:05:06:45 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 89.42.237.71 - - [25/Oct/2015:05:06:46 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 200.55.25.2 - - [25/Oct/2015:05:07:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 200.55.25.2 - - [25/Oct/2015:05:07:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 200.55.25.2 - - [25/Oct/2015:05:07:32 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 211.196.252.10 - - [25/Oct/2015:05:09:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 211.196.252.10 - - [25/Oct/2015:05:09:14 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 211.196.252.10 - - [25/Oct/2015:05:09:17 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.227.222.207 - - [25/Oct/2015:05:22:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.227.222.207 - - [25/Oct/2015:05:22:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 46.102.99.22 - - [25/Oct/2015:05:32:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.22 - - [25/Oct/2015:05:32:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.199.158 - - [25/Oct/2015:05:40:09 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.199.158 - - [25/Oct/2015:05:40:11 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.199.158 - - [25/Oct/2015:05:40:13 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.199.158 - - [25/Oct/2015:05:40:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.12.158 - - [25/Oct/2015:05:44:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.12.76 - - [25/Oct/2015:05:44:35 +0100] "GET /login_form HTTP/1.0" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.199.158 - - [25/Oct/2015:05:44:36 +0100] "POST /login_form HTTP/1.0" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.127.164 - - [25/Oct/2015:05:57:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.164 - - [25/Oct/2015:05:57:28 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.164 - - [25/Oct/2015:05:57:29 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.164 - - [25/Oct/2015:05:57:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.164 - - [25/Oct/2015:05:57:30 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.164 - - [25/Oct/2015:05:57:31 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.126.177.54 - - [25/Oct/2015:06:01:29 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.126.177.54 - - [25/Oct/2015:06:01:31 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.126.177.54 - - [25/Oct/2015:06:01:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.126.177.54 - - [25/Oct/2015:06:01:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.128.23.51 - - [25/Oct/2015:06:04:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.128.23.51 - - [25/Oct/2015:06:04:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 204.44.85.215 - - [25/Oct/2015:06:18:21 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 204.44.85.215 - - [25/Oct/2015:06:18:23 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 204.44.85.215 - - [25/Oct/2015:06:18:24 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 204.44.85.215 - - [25/Oct/2015:06:18:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 204.44.85.215 - - [25/Oct/2015:06:18:27 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 204.44.85.215 - - [25/Oct/2015:06:18:28 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 195.154.46.135 - - [25/Oct/2015:06:21:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.236.191.138 - - [25/Oct/2015:06:21:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.240.224.218 - - [25/Oct/2015:06:23:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 192.240.224.218 - - [25/Oct/2015:06:23:15 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 192.240.224.218 - - [25/Oct/2015:06:23:17 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:34.0) Gecko/20100101 Firefox/34.0" 201.234.239.28 - - [25/Oct/2015:06:51:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 201.234.239.28 - - [25/Oct/2015:06:51:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 91.196.122.132 - - [25/Oct/2015:07:42:22 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.196.122.132 - - [25/Oct/2015:07:42:23 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.196.122.132 - - [25/Oct/2015:07:42:25 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.196.122.132 - - [25/Oct/2015:07:42:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.196.122.132 - - [25/Oct/2015:07:42:27 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.196.122.132 - - [25/Oct/2015:07:42:28 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.34 - - [25/Oct/2015:07:59:44 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.34 - - [25/Oct/2015:07:59:46 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.34 - - [25/Oct/2015:07:59:48 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.34 - - [25/Oct/2015:07:59:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.34 - - [25/Oct/2015:07:59:49 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.34 - - [25/Oct/2015:07:59:51 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:08:08:18 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:08:08:21 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:08:08:22 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:08:08:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:08:08:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.64.16 - - [25/Oct/2015:08:08:28 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:13:00 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:13:03 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:13:05 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:13:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:13:13 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:13:15 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.126.177.94 - - [25/Oct/2015:08:13:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.126.177.94 - - [25/Oct/2015:08:13:30 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.126.177.94 - - [25/Oct/2015:08:13:32 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:08:34:37 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:08:34:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:08:34:39 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:08:34:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:08:34:40 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:08:34:41 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:35:53 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:35:57 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:35:59 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:36:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:36:05 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.181 - - [25/Oct/2015:08:36:08 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.196 - - [25/Oct/2015:08:43:28 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.196 - - [25/Oct/2015:08:43:31 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.196 - - [25/Oct/2015:08:43:33 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.196 - - [25/Oct/2015:08:43:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.196 - - [25/Oct/2015:08:43:40 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.196 - - [25/Oct/2015:08:43:42 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 89.36.65.53 - - [25/Oct/2015:08:49:40 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 89.36.65.53 - - [25/Oct/2015:08:49:41 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 89.36.65.53 - - [25/Oct/2015:08:49:42 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 89.36.65.53 - - [25/Oct/2015:08:49:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 89.36.65.53 - - [25/Oct/2015:08:49:44 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 89.36.65.53 - - [25/Oct/2015:08:49:45 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.254.164.173 - - [25/Oct/2015:09:18:05 +0100] "GET /linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8- HTTP/1.1" 404 12146 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:09:18:06 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:09:18:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:09:18:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:09:18:11 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:09:18:11 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 223.92.118.91 - - [25/Oct/2015:09:23:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 115.236.7.180 - - [25/Oct/2015:09:23:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 115.236.7.180 - - [25/Oct/2015:09:23:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.30.157 - - [25/Oct/2015:09:30:33 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.30.157 - - [25/Oct/2015:09:30:35 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.30.157 - - [25/Oct/2015:09:30:36 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 195.154.46.135 - - [25/Oct/2015:09:33:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.100.64 - - [25/Oct/2015:09:33:37 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.100.64 - - [25/Oct/2015:09:33:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.100.64 - - [25/Oct/2015:09:33:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 112.179.44.151 - - [25/Oct/2015:09:55:33 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 112.179.44.151 - - [25/Oct/2015:09:55:36 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 112.179.44.151 - - [25/Oct/2015:09:55:38 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 112.179.44.151 - - [25/Oct/2015:09:55:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 112.179.44.151 - - [25/Oct/2015:09:55:42 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 112.179.44.151 - - [25/Oct/2015:09:55:44 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.240.224.229 - - [25/Oct/2015:10:10:09 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.240.224.229 - - [25/Oct/2015:10:10:10 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.240.224.229 - - [25/Oct/2015:10:10:11 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.240.224.229 - - [25/Oct/2015:10:10:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.104.111 - - [25/Oct/2015:10:33:02 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24371 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.104.111 - - [25/Oct/2015:10:33:04 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.104.111 - - [25/Oct/2015:10:33:06 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.104.111 - - [25/Oct/2015:10:33:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.104.111 - - [25/Oct/2015:10:33:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.104.111 - - [25/Oct/2015:10:33:19 +0100] "POST /login_form HTTP/1.1" 200 16858 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.157.42.183 - - [25/Oct/2015:10:47:37 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24371 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.157.42.183 - - [25/Oct/2015:10:47:38 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.157.42.183 - - [25/Oct/2015:10:47:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.157.42.183 - - [25/Oct/2015:10:47:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.157.42.183 - - [25/Oct/2015:10:47:41 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.157.42.183 - - [25/Oct/2015:10:47:42 +0100] "POST /login_form HTTP/1.1" 200 16858 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 204.44.85.38 - - [25/Oct/2015:10:51:36 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 204.44.85.38 - - [25/Oct/2015:10:51:37 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 204.44.85.38 - - [25/Oct/2015:10:51:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 204.44.85.38 - - [25/Oct/2015:10:51:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 204.44.85.38 - - [25/Oct/2015:10:51:41 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 204.44.85.38 - - [25/Oct/2015:10:51:43 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 103.27.239.39 - - [25/Oct/2015:10:52:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form&last_visit:date=2015%2F10%2F13+18%3A31%3A02.492+GMT%2B2&prev_visit:date=2015%2F10%2F13+18%3A31%3A02.493+GMT%2B2&came_from_prefs=&fullname=Eileen+Coe&username=EileenCoe&email=t.h.u.c.d.v2016%40gmail.com&form.button.Register=Register&form.submitted=1 HTTP/1.1" 200 19089 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 103.27.239.39 - - [25/Oct/2015:10:52:46 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 103.27.239.39 - - [25/Oct/2015:10:52:48 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 103.27.239.39 - - [25/Oct/2015:10:52:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 103.27.239.39 - - [25/Oct/2015:10:52:51 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 103.27.239.39 - - [25/Oct/2015:10:52:54 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [25/Oct/2015:11:00:49 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [25/Oct/2015:11:00:51 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [25/Oct/2015:11:00:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [25/Oct/2015:11:00:53 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [25/Oct/2015:11:00:55 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.9.148 - - [25/Oct/2015:11:08:47 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.9.148 - - [25/Oct/2015:11:08:49 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.9.148 - - [25/Oct/2015:11:08:50 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.9.148 - - [25/Oct/2015:11:08:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.9.148 - - [25/Oct/2015:11:08:52 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.9.148 - - [25/Oct/2015:11:08:54 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.44.139 - - [25/Oct/2015:11:17:09 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.1" 200 25009 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.44.139 - - [25/Oct/2015:11:17:11 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.44.139 - - [25/Oct/2015:11:17:12 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.44.139 - - [25/Oct/2015:11:17:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.44.139 - - [25/Oct/2015:11:17:14 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.44.139 - - [25/Oct/2015:11:17:15 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.108.71.198 - - [25/Oct/2015:11:32:51 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.108.71.198 - - [25/Oct/2015:11:32:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.108.71.198 - - [25/Oct/2015:11:32:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.108.71.198 - - [25/Oct/2015:11:32:53 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.108.71.198 - - [25/Oct/2015:11:32:53 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.155.136.75 - - [25/Oct/2015:11:35:05 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.155.136.75 - - [25/Oct/2015:11:35:07 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.155.136.75 - - [25/Oct/2015:11:35:08 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.155.136.75 - - [25/Oct/2015:11:35:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.155.136.75 - - [25/Oct/2015:11:35:11 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.155.136.75 - - [25/Oct/2015:11:35:12 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.190.64 - - [25/Oct/2015:12:18:11 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.190.64 - - [25/Oct/2015:12:18:17 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.190.64 - - [25/Oct/2015:12:18:19 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.190.64 - - [25/Oct/2015:12:18:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.190.64 - - [25/Oct/2015:12:18:25 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.190.64 - - [25/Oct/2015:12:18:26 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.247.99.226 - - [25/Oct/2015:12:40:28 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.247.99.226 - - [25/Oct/2015:12:40:31 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.247.99.226 - - [25/Oct/2015:12:40:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.247.99.226 - - [25/Oct/2015:12:40:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.247.99.226 - - [25/Oct/2015:12:40:36 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.247.99.226 - - [25/Oct/2015:12:40:38 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.229.166 - - [25/Oct/2015:12:45:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.229.166 - - [25/Oct/2015:12:45:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.60.108.2 - - [25/Oct/2015:12:52:27 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.60.108.2 - - [25/Oct/2015:12:52:28 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.60.108.2 - - [25/Oct/2015:12:52:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.60.108.2 - - [25/Oct/2015:12:52:33 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.60.108.2 - - [25/Oct/2015:12:52:35 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.45.5 - - [25/Oct/2015:13:10:33 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.161.190.121 - - [25/Oct/2015:13:10:35 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.161.190.121 - - [25/Oct/2015:13:10:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.161.190.121 - - [25/Oct/2015:13:10:38 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.161.190.121 - - [25/Oct/2015:13:10:39 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 155.254.119.252 - - [25/Oct/2015:13:11:40 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 155.254.119.252 - - [25/Oct/2015:13:11:41 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 155.254.119.252 - - [25/Oct/2015:13:11:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 155.254.119.252 - - [25/Oct/2015:13:11:43 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 155.254.119.252 - - [25/Oct/2015:13:11:44 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [25/Oct/2015:13:13:59 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [25/Oct/2015:13:14:00 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [25/Oct/2015:13:14:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [25/Oct/2015:13:14:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [25/Oct/2015:13:14:02 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [25/Oct/2015:13:14:02 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.90 - - [25/Oct/2015:13:16:49 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.90 - - [25/Oct/2015:13:16:52 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.90 - - [25/Oct/2015:13:16:54 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.90 - - [25/Oct/2015:13:16:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.90 - - [25/Oct/2015:13:16:58 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.189.90 - - [25/Oct/2015:13:17:00 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 115.231.162.216 - - [25/Oct/2015:13:18:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 115.231.162.216 - - [25/Oct/2015:13:18:32 +0100] "GET / HTTP/1.1" 200 15381 "http://daniel_en_sander.basjes.nl" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 195.154.46.135 - - [25/Oct/2015:13:19:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.29.240 - - [25/Oct/2015:13:19:18 +0100] "GET /login_form HTTP/1.0" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.223.29.240 - - [25/Oct/2015:13:19:20 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.254.164.173 - - [25/Oct/2015:13:20:50 +0100] "GET /linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE- HTTP/1.1" 404 12145 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:13:20:51 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:13:20:52 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:13:20:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:13:20:56 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 23.254.164.173 - - [25/Oct/2015:13:20:56 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.112 Safari/535.1" 104.140.71.73 - - [25/Oct/2015:13:35:57 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.73 - - [25/Oct/2015:13:35:59 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.73 - - [25/Oct/2015:13:36:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.73 - - [25/Oct/2015:13:36:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.73 - - [25/Oct/2015:13:36:02 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.73 - - [25/Oct/2015:13:36:02 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.247.182.39 - - [25/Oct/2015:13:52:24 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.247.182.39 - - [25/Oct/2015:13:52:25 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.247.182.39 - - [25/Oct/2015:13:52:26 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.247.182.39 - - [25/Oct/2015:13:52:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.247.182.39 - - [25/Oct/2015:13:52:28 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.247.182.39 - - [25/Oct/2015:13:52:29 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 117.169.1.51 - - [25/Oct/2015:13:57:38 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 117.169.1.51 - - [25/Oct/2015:13:57:47 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 117.169.1.51 - - [25/Oct/2015:13:57:55 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 117.169.1.51 - - [25/Oct/2015:13:57:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 113.215.0.130 - - [25/Oct/2015:14:25:42 +0100] "GET http://howto.basjes.nl/join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 113.215.0.130 - - [25/Oct/2015:14:25:45 +0100] "POST http://howto.basjes.nl/join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 113.215.0.130 - - [25/Oct/2015:14:25:51 +0100] "GET http://howto.basjes.nl/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 113.215.0.130 - - [25/Oct/2015:14:25:55 +0100] "GET http://howto.basjes.nl/login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 113.215.0.130 - - [25/Oct/2015:14:25:58 +0100] "POST http://howto.basjes.nl/login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.104 - - [25/Oct/2015:15:03:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.104 - - [25/Oct/2015:15:03:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [25/Oct/2015:15:08:23 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [25/Oct/2015:15:08:25 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [25/Oct/2015:15:08:25 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [25/Oct/2015:15:08:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [25/Oct/2015:15:08:27 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [25/Oct/2015:15:08:28 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.196.63 - - [25/Oct/2015:16:02:58 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.196.63 - - [25/Oct/2015:16:03:00 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.196.63 - - [25/Oct/2015:16:03:01 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.196.63 - - [25/Oct/2015:16:03:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.200.60 - - [25/Oct/2015:16:03:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.200.60 - - [25/Oct/2015:16:03:35 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.200.60 - - [25/Oct/2015:16:03:36 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.161.163.180 - - [25/Oct/2015:16:35:06 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.161.163.180 - - [25/Oct/2015:16:35:08 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.161.163.180 - - [25/Oct/2015:16:35:10 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.81 - - [25/Oct/2015:16:46:54 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.81 - - [25/Oct/2015:16:46:55 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.81 - - [25/Oct/2015:16:46:56 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.81 - - [25/Oct/2015:16:46:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.81 - - [25/Oct/2015:16:46:58 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.81 - - [25/Oct/2015:16:46:59 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.106.127 - - [25/Oct/2015:17:01:29 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.106.127 - - [25/Oct/2015:17:01:33 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.106.127 - - [25/Oct/2015:17:01:36 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.106.127 - - [25/Oct/2015:17:01:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.106.127 - - [25/Oct/2015:17:01:40 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.106.127 - - [25/Oct/2015:17:01:42 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 198.46.242.48 - - [25/Oct/2015:17:06:19 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 198.46.242.48 - - [25/Oct/2015:17:06:20 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 198.46.242.48 - - [25/Oct/2015:17:06:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 198.46.242.48 - - [25/Oct/2015:17:06:27 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 198.46.242.48 - - [25/Oct/2015:17:06:28 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.60.151 - - [25/Oct/2015:17:11:46 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.60.151 - - [25/Oct/2015:17:11:48 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.60.151 - - [25/Oct/2015:17:11:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.60.151 - - [25/Oct/2015:17:12:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.60.151 - - [25/Oct/2015:17:12:17 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.60.151 - - [25/Oct/2015:17:12:19 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 62.210.141.226 - - [25/Oct/2015:17:23:39 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.1" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.3.190.14 - - [25/Oct/2015:17:23:40 +0100] "GET /join_form HTTP/1.1" 200 11114 "-" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.3.190.14 - - [25/Oct/2015:17:23:41 +0100] "POST /join_form HTTP/1.1" 302 9093 "-" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.3.190.14 - - [25/Oct/2015:17:23:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "-" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 62.210.141.226 - - [25/Oct/2015:17:29:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 69.12.66.210 - - [25/Oct/2015:17:29:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 46.102.99.131 - - [25/Oct/2015:17:37:07 +0100] "GET /sitemap HTTP/1.0" 200 11975 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [25/Oct/2015:17:37:08 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [25/Oct/2015:17:37:09 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [25/Oct/2015:17:37:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [25/Oct/2015:17:37:12 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [25/Oct/2015:17:37:14 +0100] "POST /login_form HTTP/1.1" 200 18241 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.175.219.94 - - [25/Oct/2015:17:53:41 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.219.94 - - [25/Oct/2015:17:53:45 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.219.94 - - [25/Oct/2015:17:53:46 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.219.94 - - [25/Oct/2015:17:53:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.219.94 - - [25/Oct/2015:17:53:49 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.219.94 - - [25/Oct/2015:17:53:51 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 110.208.27.102 - - [25/Oct/2015:17:56:59 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 110.208.27.102 - - [25/Oct/2015:17:57:01 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 110.208.27.102 - - [25/Oct/2015:17:57:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 110.208.27.102 - - [25/Oct/2015:17:57:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 110.208.27.102 - - [25/Oct/2015:17:57:05 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 110.208.27.102 - - [25/Oct/2015:17:57:08 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 104.254.212.109 - - [25/Oct/2015:18:01:09 +0100] "GET /splittable-gzip HTTP/1.1" 200 27873 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.254.212.109 - - [25/Oct/2015:18:01:10 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.254.212.109 - - [25/Oct/2015:18:01:11 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.254.212.109 - - [25/Oct/2015:18:01:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.254.212.109 - - [25/Oct/2015:18:01:13 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.254.212.109 - - [25/Oct/2015:18:01:14 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 62.210.141.226 - - [25/Oct/2015:18:08:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:18:22:13 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:18:22:13 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:18:22:14 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:18:22:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:18:22:16 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.99.244.139 - - [25/Oct/2015:18:22:17 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 94.249.245.51 - - [25/Oct/2015:18:44:42 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.249.245.51 - - [25/Oct/2015:18:44:43 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.249.245.51 - - [25/Oct/2015:18:44:44 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.249.245.51 - - [25/Oct/2015:18:44:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.249.245.51 - - [25/Oct/2015:18:44:46 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.249.245.51 - - [25/Oct/2015:18:44:47 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.97.153 - - [25/Oct/2015:18:46:38 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.97.153 - - [25/Oct/2015:18:46:40 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.97.153 - - [25/Oct/2015:18:46:43 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.97.153 - - [25/Oct/2015:18:46:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.97.153 - - [25/Oct/2015:18:46:49 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.97.153 - - [25/Oct/2015:18:46:54 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.222.163 - - [25/Oct/2015:18:52:10 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.222.163 - - [25/Oct/2015:18:52:12 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.222.163 - - [25/Oct/2015:18:52:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.222.163 - - [25/Oct/2015:18:52:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.5.244 - - [25/Oct/2015:18:52:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.200.24.243 - - [25/Oct/2015:19:31:51 +0100] "GET / HTTP/1.0" 200 20526 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.200.24.243 - - [25/Oct/2015:19:31:52 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.200.24.243 - - [25/Oct/2015:19:31:54 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.200.24.243 - - [25/Oct/2015:19:31:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.200.24.243 - - [25/Oct/2015:19:31:57 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 192.200.24.243 - - [25/Oct/2015:19:31:58 +0100] "POST /login_form HTTP/1.1" 200 18402 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.224.141 - - [25/Oct/2015:19:31:59 +0100] "GET / HTTP/1.1" 200 20526 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.224.141 - - [25/Oct/2015:19:32:00 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.224.141 - - [25/Oct/2015:19:32:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.224.141 - - [25/Oct/2015:19:32:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.224.141 - - [25/Oct/2015:19:32:04 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 172.245.224.141 - - [25/Oct/2015:19:32:05 +0100] "POST /login_form HTTP/1.1" 200 18402 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 186.206.255.185 - - [25/Oct/2015:19:49:37 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 186.206.255.185 - - [25/Oct/2015:19:49:57 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 186.206.255.185 - - [25/Oct/2015:19:50:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 186.206.255.185 - - [25/Oct/2015:19:50:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 186.206.255.185 - - [25/Oct/2015:19:50:43 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 186.206.255.185 - - [25/Oct/2015:19:50:51 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 45.33.146.75 - - [25/Oct/2015:20:06:03 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 45.33.146.75 - - [25/Oct/2015:20:06:06 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 45.33.146.75 - - [25/Oct/2015:20:06:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 45.33.146.75 - - [25/Oct/2015:20:06:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 45.33.146.75 - - [25/Oct/2015:20:06:12 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 45.33.146.75 - - [25/Oct/2015:20:06:13 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.0.248 - - [25/Oct/2015:20:08:30 +0100] "GET /places HTTP/1.0" 200 19407 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.0.248 - - [25/Oct/2015:20:08:32 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.0.248 - - [25/Oct/2015:20:08:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.0.248 - - [25/Oct/2015:20:08:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.0.248 - - [25/Oct/2015:20:08:35 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.172.0.248 - - [25/Oct/2015:20:08:36 +0100] "POST /login_form HTTP/1.1" 200 18402 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.177.240 - - [25/Oct/2015:20:27:45 +0100] "GET /author/nielsbasjes HTTP/1.0" 200 15519 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [25/Oct/2015:20:27:52 +0100] "GET /join_form HTTP/1.0" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [25/Oct/2015:20:27:53 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [25/Oct/2015:20:27:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [25/Oct/2015:20:27:54 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [25/Oct/2015:20:27:55 +0100] "POST /login_form HTTP/1.1" 200 18241 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 62.210.204.180 - - [25/Oct/2015:21:18:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 62.210.204.180 - - [25/Oct/2015:21:18:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.108 - - [25/Oct/2015:21:46:44 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.108 - - [25/Oct/2015:21:46:46 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.108 - - [25/Oct/2015:21:46:47 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.108 - - [25/Oct/2015:21:46:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.108 - - [25/Oct/2015:21:46:48 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.140.71.108 - - [25/Oct/2015:21:46:50 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 62.210.204.180 - - [25/Oct/2015:22:13:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 62.210.204.180 - - [25/Oct/2015:22:13:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 46.102.99.140 - - [25/Oct/2015:22:25:34 +0100] "GET /sitemap HTTP/1.0" 200 11975 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [25/Oct/2015:22:25:35 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [25/Oct/2015:22:25:36 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [25/Oct/2015:22:25:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [25/Oct/2015:22:25:41 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [25/Oct/2015:22:25:44 +0100] "POST /login_form HTTP/1.1" 200 18241 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 91.99.99.59 - - [25/Oct/2015:22:45:30 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 91.99.99.59 - - [25/Oct/2015:22:45:32 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 125.140.118.12 - - [25/Oct/2015:22:45:41 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 125.140.118.12 - - [25/Oct/2015:22:45:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 125.140.118.12 - - [25/Oct/2015:22:45:47 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 125.140.118.12 - - [25/Oct/2015:22:45:50 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 81.83.39.195 - - [25/Oct/2015:23:01:05 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 81.83.39.195 - - [25/Oct/2015:23:01:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 81.83.39.195 - - [25/Oct/2015:23:01:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 81.83.39.195 - - [25/Oct/2015:23:01:18 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 170.130.66.205 - - [25/Oct/2015:23:25:12 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 170.130.66.205 - - [25/Oct/2015:23:25:24 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 170.130.66.205 - - [25/Oct/2015:23:25:28 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 170.130.66.205 - - [25/Oct/2015:23:25:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 170.130.66.205 - - [25/Oct/2015:23:25:39 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 170.130.66.205 - - [25/Oct/2015:23:25:46 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.12.39 - - [25/Oct/2015:23:40:46 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.39 - - [25/Oct/2015:23:40:48 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.39 - - [25/Oct/2015:23:40:49 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.39 - - [25/Oct/2015:23:40:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.39 - - [25/Oct/2015:23:40:52 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.39 - - [25/Oct/2015:23:40:53 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:00:00:02 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:00:00:04 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:00:00:05 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:00:00:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:00:00:07 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:00:00:08 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 121.204.74.138 - - [26/Oct/2015:00:13:17 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 192.210.223.92 - - [26/Oct/2015:00:14:15 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.92 - - [26/Oct/2015:00:14:18 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.92 - - [26/Oct/2015:00:14:18 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.92 - - [26/Oct/2015:00:14:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.92 - - [26/Oct/2015:00:14:20 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 192.210.223.92 - - [26/Oct/2015:00:14:21 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.91.209 - - [26/Oct/2015:00:27:38 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.91.209 - - [26/Oct/2015:00:27:39 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.91.209 - - [26/Oct/2015:00:27:40 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.91.209 - - [26/Oct/2015:00:27:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.91.209 - - [26/Oct/2015:00:27:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.91.209 - - [26/Oct/2015:00:27:43 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.136.18.6 - - [26/Oct/2015:00:31:03 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.136.18.6 - - [26/Oct/2015:00:31:09 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.136.18.6 - - [26/Oct/2015:00:31:13 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.136.18.6 - - [26/Oct/2015:00:31:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.136.18.6 - - [26/Oct/2015:00:31:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 190.136.18.6 - - [26/Oct/2015:00:31:30 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 50.7.8.74 - - [26/Oct/2015:00:44:20 +0100] "GET / HTTP/1.0" 200 15377 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 50.7.8.74 - - [26/Oct/2015:00:44:25 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 50.7.8.74 - - [26/Oct/2015:00:44:34 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 50.7.8.74 - - [26/Oct/2015:00:44:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.103.37 - - [26/Oct/2015:00:46:18 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.103.37 - - [26/Oct/2015:00:46:20 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.103.37 - - [26/Oct/2015:00:46:22 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.103.37 - - [26/Oct/2015:00:46:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.103.37 - - [26/Oct/2015:00:46:25 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.231.24.17 - - [26/Oct/2015:00:46:31 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.17 - - [26/Oct/2015:00:46:33 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.103.37 - - [26/Oct/2015:00:46:33 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.231.24.17 - - [26/Oct/2015:00:46:34 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.17 - - [26/Oct/2015:00:46:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.17 - - [26/Oct/2015:00:46:36 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.17 - - [26/Oct/2015:00:46:38 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [26/Oct/2015:01:24:10 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [26/Oct/2015:01:24:12 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [26/Oct/2015:01:24:13 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [26/Oct/2015:01:24:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [26/Oct/2015:01:24:15 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.132.106 - - [26/Oct/2015:01:24:16 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.102.54 - - [26/Oct/2015:01:38:38 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.102.54 - - [26/Oct/2015:01:38:40 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.102.54 - - [26/Oct/2015:01:38:42 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.102.54 - - [26/Oct/2015:01:38:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.102.54 - - [26/Oct/2015:01:38:46 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.102.54 - - [26/Oct/2015:01:38:49 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.52.212.158 - - [26/Oct/2015:01:52:59 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.52.212.158 - - [26/Oct/2015:01:53:00 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.52.212.158 - - [26/Oct/2015:01:53:01 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.52.212.158 - - [26/Oct/2015:01:53:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.52.212.158 - - [26/Oct/2015:01:53:04 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.52.212.158 - - [26/Oct/2015:01:53:05 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 211.103.148.66 - - [26/Oct/2015:01:57:46 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 211.103.148.66 - - [26/Oct/2015:01:57:50 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 211.103.148.66 - - [26/Oct/2015:01:57:52 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.100.171 - - [26/Oct/2015:02:29:18 +0100] "GET / HTTP/1.0" 200 15377 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.100.171 - - [26/Oct/2015:02:29:19 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.100.171 - - [26/Oct/2015:02:29:21 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.100.171 - - [26/Oct/2015:02:29:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 196.196.34.116 - - [26/Oct/2015:02:30:10 +0100] "GET / HTTP/1.0" 200 17053 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 196.196.34.116 - - [26/Oct/2015:02:30:12 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 196.196.34.116 - - [26/Oct/2015:02:30:13 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 196.196.34.116 - - [26/Oct/2015:02:30:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 196.196.34.116 - - [26/Oct/2015:02:30:14 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 196.196.34.116 - - [26/Oct/2015:02:30:14 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.73.221 - - [26/Oct/2015:02:33:03 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.73.221 - - [26/Oct/2015:02:33:05 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.73.221 - - [26/Oct/2015:02:33:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.73.221 - - [26/Oct/2015:02:33:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.73.221 - - [26/Oct/2015:02:33:11 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.73.221 - - [26/Oct/2015:02:33:12 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.176.33 - - [26/Oct/2015:02:41:26 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.176.33 - - [26/Oct/2015:02:41:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.176.33 - - [26/Oct/2015:02:41:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.176.33 - - [26/Oct/2015:02:41:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.176.33 - - [26/Oct/2015:02:41:34 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.176.33 - - [26/Oct/2015:02:41:36 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.247 - - [26/Oct/2015:02:53:59 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.89.247 - - [26/Oct/2015:02:54:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.89.247 - - [26/Oct/2015:02:54:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.89.247 - - [26/Oct/2015:02:54:03 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.89.247 - - [26/Oct/2015:02:54:04 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 222.138.66.77 - - [26/Oct/2015:02:59:45 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 222.138.66.77 - - [26/Oct/2015:02:59:58 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 222.138.66.77 - - [26/Oct/2015:03:00:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 222.138.66.77 - - [26/Oct/2015:03:00:33 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 222.138.66.77 - - [26/Oct/2015:03:00:38 +0100] "POST /login_form HTTP/1.0" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.231.24.84 - - [26/Oct/2015:03:18:11 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.84 - - [26/Oct/2015:03:18:14 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.84 - - [26/Oct/2015:03:18:15 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.84 - - [26/Oct/2015:03:18:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.84 - - [26/Oct/2015:03:18:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.84 - - [26/Oct/2015:03:18:18 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 188.211.162.129 - - [26/Oct/2015:03:31:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 188.211.162.129 - - [26/Oct/2015:03:32:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 167.160.127.104 - - [26/Oct/2015:03:42:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 167.160.127.104 - - [26/Oct/2015:03:42:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.177.240 - - [26/Oct/2015:04:10:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.152 - - [26/Oct/2015:04:10:45 +0100] "GET /join_form HTTP/1.0" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.152 - - [26/Oct/2015:04:10:45 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.152 - - [26/Oct/2015:04:10:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.152 - - [26/Oct/2015:04:10:46 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.152 - - [26/Oct/2015:04:10:46 +0100] "POST /login_form HTTP/1.1" 200 18237 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 93.152.141.25 - - [26/Oct/2015:04:12:53 +0100] "GET / HTTP/1.1" 302 285 "http://www.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:12:53 +0100] "GET / HTTP/1.1" 200 20474 "http://www.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:12:53 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:12:54 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:12:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:12:55 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:12:56 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.231.24.101 - - [26/Oct/2015:04:28:27 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.101 - - [26/Oct/2015:04:28:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.101 - - [26/Oct/2015:04:28:30 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.101 - - [26/Oct/2015:04:28:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.101 - - [26/Oct/2015:04:28:32 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 23.231.24.101 - - [26/Oct/2015:04:28:33 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.113.117 - - [26/Oct/2015:04:37:58 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.113.117 - - [26/Oct/2015:04:37:59 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.113.117 - - [26/Oct/2015:04:38:01 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.113.117 - - [26/Oct/2015:04:38:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.113.117 - - [26/Oct/2015:04:38:03 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.158.113.117 - - [26/Oct/2015:04:38:04 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.161.83.180 - - [26/Oct/2015:04:43:07 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.161.83.180 - - [26/Oct/2015:04:43:09 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.161.83.180 - - [26/Oct/2015:04:43:10 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.161.83.180 - - [26/Oct/2015:04:43:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.161.83.180 - - [26/Oct/2015:04:43:12 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 107.161.83.180 - - [26/Oct/2015:04:43:13 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 93.152.141.25 - - [26/Oct/2015:04:44:34 +0100] "GET / HTTP/1.1" 302 285 "http://www.basjes.nl" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:44:35 +0100] "GET / HTTP/1.1" 200 20474 "http://www.basjes.nl" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:44:35 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:44:36 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:44:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:44:37 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.152.141.25 - - [26/Oct/2015:04:44:37 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.19.69 - - [26/Oct/2015:04:52:36 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.19.69 - - [26/Oct/2015:04:52:39 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.19.69 - - [26/Oct/2015:04:52:40 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.19.69 - - [26/Oct/2015:04:52:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.19.69 - - [26/Oct/2015:04:52:43 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 104.144.19.69 - - [26/Oct/2015:04:52:45 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.238.253 - - [26/Oct/2015:05:11:36 +0100] "GET / HTTP/1.0" 200 17053 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.238.253 - - [26/Oct/2015:05:11:38 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.238.253 - - [26/Oct/2015:05:11:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.238.253 - - [26/Oct/2015:05:11:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.238.253 - - [26/Oct/2015:05:11:43 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 23.95.238.253 - - [26/Oct/2015:05:11:45 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.184.47 - - [26/Oct/2015:05:18:36 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 12881 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.196.24 - - [26/Oct/2015:05:21:23 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.158.196.24 - - [26/Oct/2015:05:21:26 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.8.215 - - [26/Oct/2015:05:21:44 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:05:38:02 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:05:38:03 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:05:38:05 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:05:38:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:05:38:09 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 64.110.135.40 - - [26/Oct/2015:05:38:10 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 1.0.184.47 - - [26/Oct/2015:05:47:11 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.184.47 - - [26/Oct/2015:05:47:16 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.184.47 - - [26/Oct/2015:05:47:18 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.184.47 - - [26/Oct/2015:05:47:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.184.47 - - [26/Oct/2015:05:47:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.184.47 - - [26/Oct/2015:05:47:28 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.177.235 - - [26/Oct/2015:06:35:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.177.191 - - [26/Oct/2015:06:35:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 5.175.140.91 - - [26/Oct/2015:07:01:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:07:01:09 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:07:01:10 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:07:01:10 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:07:01:11 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:07:01:11 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.195.201 - - [26/Oct/2015:07:02:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.195.201 - - [26/Oct/2015:07:02:25 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.195.201 - - [26/Oct/2015:07:02:26 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.195.201 - - [26/Oct/2015:07:02:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.195.201 - - [26/Oct/2015:07:02:27 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.195.201 - - [26/Oct/2015:07:02:28 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.12.192 - - [26/Oct/2015:07:04:12 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.192 - - [26/Oct/2015:07:04:14 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.192 - - [26/Oct/2015:07:04:15 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.192 - - [26/Oct/2015:07:04:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.192 - - [26/Oct/2015:07:04:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 158.222.12.192 - - [26/Oct/2015:07:04:18 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:07:42 +0100] "GET /search_form HTTP/1.1" 200 29978 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:07:44 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:07:45 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:07:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [26/Oct/2015:07:20:58 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [26/Oct/2015:07:20:59 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [26/Oct/2015:07:21:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [26/Oct/2015:07:21:02 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 178.216.54.163 - - [26/Oct/2015:07:21:03 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:27:32 +0100] "GET /contact-info HTTP/1.1" 200 15797 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:27:33 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:27:34 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:27:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 180.180.108.189 - - [26/Oct/2015:07:29:22 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:07:29:25 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:07:29:26 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:07:29:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:07:29:30 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:07:29:32 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 66.150.34.161 - - [26/Oct/2015:07:33:31 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 66.150.34.161 - - [26/Oct/2015:07:33:32 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 66.150.34.161 - - [26/Oct/2015:07:33:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 66.150.34.161 - - [26/Oct/2015:07:33:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 66.150.34.161 - - [26/Oct/2015:07:33:35 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 66.150.34.161 - - [26/Oct/2015:07:33:36 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 31.187.79.201 - - [26/Oct/2015:07:34:14 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.187.79.201 - - [26/Oct/2015:07:34:14 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.187.79.201 - - [26/Oct/2015:07:34:15 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.187.79.201 - - [26/Oct/2015:07:34:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.187.79.201 - - [26/Oct/2015:07:34:16 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.187.79.201 - - [26/Oct/2015:07:34:16 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:44:37 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:44:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:44:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:44:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [26/Oct/2015:07:46:15 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [26/Oct/2015:07:46:17 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [26/Oct/2015:07:46:17 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [26/Oct/2015:07:46:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [26/Oct/2015:07:46:19 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 31.220.113.224 - - [26/Oct/2015:07:46:19 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:49:50 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:49:51 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:49:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:07:49:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 5.1; rv:35.0) Gecko/20100101 Firefox/35.0" 216.244.81.34 - - [26/Oct/2015:08:08:30 +0100] "GET /contact-info HTTP/1.1" 200 15797 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:08:08:31 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:08:08:32 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:08:08:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:08:54:18 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:08:54:21 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:08:54:22 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:08:54:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:08:54:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.108.189 - - [26/Oct/2015:08:54:28 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.95.201.243 - - [26/Oct/2015:08:59:11 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.95.201.243 - - [26/Oct/2015:08:59:12 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.95.201.243 - - [26/Oct/2015:08:59:14 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.95.201.243 - - [26/Oct/2015:08:59:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.95.201.243 - - [26/Oct/2015:08:59:16 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.95.201.243 - - [26/Oct/2015:08:59:17 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:08:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:08:52 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:08:53 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:12:36 +0100] "GET /splittable-gzip HTTP/1.1" 200 27869 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:12:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:12:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:12:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:24:12 +0100] "GET /friends HTTP/1.1" 200 17524 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:24:13 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:24:14 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:24:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.12.82.174 - - [26/Oct/2015:09:25:51 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.174 - - [26/Oct/2015:09:25:53 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.174 - - [26/Oct/2015:09:25:54 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.174 - - [26/Oct/2015:09:25:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.174 - - [26/Oct/2015:09:25:55 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.174 - - [26/Oct/2015:09:25:56 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 107.173.209.101 - - [26/Oct/2015:09:26:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.173.209.101 - - [26/Oct/2015:09:26:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:26:40 +0100] "GET /open-source HTTP/1.1" 200 17525 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:26:41 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:26:42 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:26:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.199.158 - - [26/Oct/2015:09:30:19 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:32:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:32:39 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:32:40 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.254.164.173 - - [26/Oct/2015:09:33:41 +0100] "GET /linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE- HTTP/1.1" 404 12145 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:09:33:42 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:09:33:43 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:09:33:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:09:33:45 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:09:33:45 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 216.244.81.34 - - [26/Oct/2015:09:45:36 +0100] "GET /friends HTTP/1.1" 200 17524 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:45:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:45:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:45:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:49:10 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:49:11 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:49:12 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:25 +0100] "GET /splittable-gzip HTTP/1.1" 200 27869 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:27 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:28 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:47 +0100] "GET /open-source HTTP/1.1" 200 17525 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:48 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:49 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:54:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:57:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:57:54 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:57:55 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:58:48 +0100] "GET /work HTTP/1.1" 200 17881 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:58:49 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:58:50 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:09:58:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.128.23.51 - - [26/Oct/2015:10:05:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.128.23.51 - - [26/Oct/2015:10:05:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:08:10 +0100] "GET /accessibility-info HTTP/1.1" 200 20622 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:08:11 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:08:12 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:08:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:14:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:14:46 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:14:47 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:21:36 +0100] "GET /work HTTP/1.1" 200 17881 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:21:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:21:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:21:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:42:45 +0100] "GET /accessibility-info HTTP/1.1" 200 20622 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:42:47 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:42:48 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:42:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:51:02 +0100] "GET /sitemap HTTP/1.1" 200 12065 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:51:03 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:51:04 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:10:51:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.107.255 - - [26/Oct/2015:10:53:20 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.107.255 - - [26/Oct/2015:10:53:25 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.107.255 - - [26/Oct/2015:10:53:26 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.107.255 - - [26/Oct/2015:10:53:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.107.255 - - [26/Oct/2015:10:53:29 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.107.255 - - [26/Oct/2015:10:53:30 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 61.162.184.21 - - [26/Oct/2015:11:07:37 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 91.217.42.1 - - [26/Oct/2015:11:08:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:14:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:14:23 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:14:23 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.127.184 - - [26/Oct/2015:11:19:51 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.1" 200 25005 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.127.184 - - [26/Oct/2015:11:19:52 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.127.184 - - [26/Oct/2015:11:19:53 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.127.184 - - [26/Oct/2015:11:19:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:20:41 +0100] "GET /sitemap HTTP/1.1" 200 12065 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:20:42 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:20:43 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:20:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [26/Oct/2015:11:20:50 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [26/Oct/2015:11:20:51 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [26/Oct/2015:11:20:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [26/Oct/2015:11:20:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [26/Oct/2015:11:20:55 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [26/Oct/2015:11:20:56 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.223.45.40 - - [26/Oct/2015:11:22:45 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.223.45.40 - - [26/Oct/2015:11:22:46 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:26:10 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:26:11 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:26:12 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:33:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:33:08 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:33:09 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.254.249.15 - - [26/Oct/2015:11:34:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.254.249.15 - - [26/Oct/2015:11:34:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:37:31 +0100] "GET / HTTP/1.1" 302 281 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:37:32 +0100] "GET / HTTP/1.1" 200 20474 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:37:33 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:37:34 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:37:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.140.71.84 - - [26/Oct/2015:11:47:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.140.71.84 - - [26/Oct/2015:11:47:40 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.140.71.84 - - [26/Oct/2015:11:47:41 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.140.71.84 - - [26/Oct/2015:11:47:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.140.71.84 - - [26/Oct/2015:11:47:43 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.140.71.84 - - [26/Oct/2015:11:47:44 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:53:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:53:41 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:53:42 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 220.181.143.14 - - [26/Oct/2015:11:54:22 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 220.181.143.14 - - [26/Oct/2015:11:54:24 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 220.181.143.14 - - [26/Oct/2015:11:54:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:05 +0100] "GET / HTTP/1.1" 302 281 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:05 +0100] "GET / HTTP/1.1" 200 20474 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 212.83.183.34 - - [26/Oct/2015:11:59:05 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:07 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:08 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:21 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:22 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:40 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:11:59:41 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:02:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:02:32 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:02:32 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.15.195 - - [26/Oct/2015:12:06:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.15.195 - - [26/Oct/2015:12:06:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 101.71.27.120 - - [26/Oct/2015:12:06:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 101.71.27.120 - - [26/Oct/2015:12:06:44 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 101.71.27.120 - - [26/Oct/2015:12:06:47 +0100] "POST /login_form HTTP/1.0" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:14:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:14:04 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:14:05 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.116.194 - - [26/Oct/2015:12:27:15 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.116.194 - - [26/Oct/2015:12:27:17 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.116.194 - - [26/Oct/2015:12:27:19 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.116.194 - - [26/Oct/2015:12:27:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.116.194 - - [26/Oct/2015:12:27:22 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.116.194 - - [26/Oct/2015:12:27:24 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:34:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:34:01 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:34:02 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.254.164.173 - - [26/Oct/2015:12:41:09 +0100] "GET /linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE- HTTP/1.1" 404 12145 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:12:41:10 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:12:41:15 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:12:41:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:12:41:18 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:12:41:21 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 158.222.15.194 - - [26/Oct/2015:12:43:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.15.194 - - [26/Oct/2015:12:43:49 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.15.194 - - [26/Oct/2015:12:43:50 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:45:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:45:05 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:45:06 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.191.52 - - [26/Oct/2015:12:45:44 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.191.52 - - [26/Oct/2015:12:45:46 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.191.52 - - [26/Oct/2015:12:45:49 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.191.52 - - [26/Oct/2015:12:45:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.191.52 - - [26/Oct/2015:12:45:52 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.191.52 - - [26/Oct/2015:12:45:54 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:51:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:51:05 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:12:51:06 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:13:03:59 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19418 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:13:04:01 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.140.91 - - [26/Oct/2015:13:04:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 148.251.65.34 - - [26/Oct/2015:13:13:13 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.15.61 - - [26/Oct/2015:13:13:14 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.110.250 - - [26/Oct/2015:13:13:16 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.110.250 - - [26/Oct/2015:13:13:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.110.250 - - [26/Oct/2015:13:13:19 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 167.160.110.250 - - [26/Oct/2015:13:13:20 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:13:29:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:13:29:02 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:13:29:03 +0100] "POST /login_form HTTP/1.1" 200 18398 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 14.139.172.170 - - [26/Oct/2015:13:33:55 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.1" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 14.139.172.170 - - [26/Oct/2015:13:33:58 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 14.139.172.170 - - [26/Oct/2015:13:34:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 14.139.172.170 - - [26/Oct/2015:13:34:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.161.83.180 - - [26/Oct/2015:13:43:33 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 107.161.83.180 - - [26/Oct/2015:13:43:36 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 107.161.83.180 - - [26/Oct/2015:13:43:37 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 107.161.83.180 - - [26/Oct/2015:13:43:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 107.161.83.180 - - [26/Oct/2015:13:43:39 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 107.161.83.180 - - [26/Oct/2015:13:43:40 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 216.244.81.34 - - [26/Oct/2015:13:44:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:13:44:23 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:13:44:24 +0100] "POST /login_form HTTP/1.1" 200 18398 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 24.157.37.61 - - [26/Oct/2015:13:52:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 24.157.37.61 - - [26/Oct/2015:13:52:47 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 24.157.37.61 - - [26/Oct/2015:13:52:47 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:14:09:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:14:09:17 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.244.81.34 - - [26/Oct/2015:14:09:18 +0100] "POST /login_form HTTP/1.1" 200 18398 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 52.11.126.199 - - [26/Oct/2015:14:11:51 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 52.11.126.199 - - [26/Oct/2015:14:11:53 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 52.11.126.199 - - [26/Oct/2015:14:11:55 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 52.11.126.199 - - [26/Oct/2015:14:11:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 52.11.126.199 - - [26/Oct/2015:14:11:57 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 52.11.126.199 - - [26/Oct/2015:14:11:59 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.126.192.238 - - [26/Oct/2015:14:12:20 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.126.192.238 - - [26/Oct/2015:14:12:22 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.126.192.238 - - [26/Oct/2015:14:12:24 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.126.192.238 - - [26/Oct/2015:14:12:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.126.192.238 - - [26/Oct/2015:14:12:27 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.126.192.238 - - [26/Oct/2015:14:12:29 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.119.149.217 - - [26/Oct/2015:14:22:25 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.217 - - [26/Oct/2015:14:22:26 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.217 - - [26/Oct/2015:14:22:27 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.217 - - [26/Oct/2015:14:22:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.217 - - [26/Oct/2015:14:22:29 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.217 - - [26/Oct/2015:14:22:29 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.23.234.158 - - [26/Oct/2015:14:28:23 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:14:28:25 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:14:28:26 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:14:28:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:14:28:29 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:14:28:30 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.208.103.56 - - [26/Oct/2015:14:35:23 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.208.103.56 - - [26/Oct/2015:14:35:31 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.208.103.56 - - [26/Oct/2015:14:35:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.208.103.56 - - [26/Oct/2015:14:35:42 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.208.103.56 - - [26/Oct/2015:14:35:44 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [26/Oct/2015:14:38:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [26/Oct/2015:14:38:58 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [26/Oct/2015:14:38:59 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [26/Oct/2015:14:38:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [26/Oct/2015:14:39:00 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [26/Oct/2015:14:39:00 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 69.46.64.183 - - [26/Oct/2015:14:54:58 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 69.46.64.183 - - [26/Oct/2015:14:55:00 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 69.46.64.183 - - [26/Oct/2015:14:55:01 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 69.46.64.183 - - [26/Oct/2015:14:55:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 69.46.64.183 - - [26/Oct/2015:14:55:04 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 69.46.64.183 - - [26/Oct/2015:14:55:06 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:15:55:01 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:15:55:09 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:15:55:11 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:15:55:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:15:55:15 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:15:55:17 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.113.146 - - [26/Oct/2015:15:57:35 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.113.146 - - [26/Oct/2015:15:57:37 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.113.146 - - [26/Oct/2015:15:57:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.113.146 - - [26/Oct/2015:15:57:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.113.146 - - [26/Oct/2015:15:57:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.113.146 - - [26/Oct/2015:15:57:43 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.23.33.25 - - [26/Oct/2015:16:07:26 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.44.112.144 - - [26/Oct/2015:16:07:29 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.44.112.144 - - [26/Oct/2015:16:07:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.44.112.144 - - [26/Oct/2015:16:07:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.44.112.144 - - [26/Oct/2015:16:07:34 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.44.112.144 - - [26/Oct/2015:16:07:38 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.70.177 - - [26/Oct/2015:16:35:47 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.70.177 - - [26/Oct/2015:16:35:50 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.70.177 - - [26/Oct/2015:16:35:51 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.70.177 - - [26/Oct/2015:16:35:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.70.177 - - [26/Oct/2015:16:35:55 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.70.177 - - [26/Oct/2015:16:35:56 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 212.83.141.47 - - [26/Oct/2015:16:46:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.14.51 - - [26/Oct/2015:16:49:10 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.0" 200 25005 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.14.51 - - [26/Oct/2015:16:49:12 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.14.51 - - [26/Oct/2015:16:49:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.14.51 - - [26/Oct/2015:16:49:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.14.51 - - [26/Oct/2015:16:49:18 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.14.51 - - [26/Oct/2015:16:49:20 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.138.121.115 - - [26/Oct/2015:16:51:15 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:17:01:05 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:17:01:08 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:17:01:11 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:17:01:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:17:01:15 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 1.0.182.20 - - [26/Oct/2015:17:01:17 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.23.33.25 - - [26/Oct/2015:17:01:48 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.239 - - [26/Oct/2015:17:01:49 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.239 - - [26/Oct/2015:17:01:51 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.239 - - [26/Oct/2015:17:01:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.239 - - [26/Oct/2015:17:01:54 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.3.106.205 - - [26/Oct/2015:17:01:55 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 107.158.89.239 - - [26/Oct/2015:17:01:56 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.3.106.205 - - [26/Oct/2015:17:01:57 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.3.106.205 - - [26/Oct/2015:17:01:58 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.3.106.205 - - [26/Oct/2015:17:01:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.3.106.205 - - [26/Oct/2015:17:02:00 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.3.106.205 - - [26/Oct/2015:17:02:01 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 23.254.164.173 - - [26/Oct/2015:17:02:14 +0100] "GET /linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE- HTTP/1.1" 404 12145 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:17:02:15 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:17:02:16 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:17:02:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:17:02:19 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [26/Oct/2015:17:02:21 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 172.245.225.213 - - [26/Oct/2015:17:16:51 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 172.245.225.213 - - [26/Oct/2015:17:16:53 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 172.245.225.213 - - [26/Oct/2015:17:16:54 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 172.245.225.213 - - [26/Oct/2015:17:16:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 172.245.225.213 - - [26/Oct/2015:17:16:56 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 172.245.225.213 - - [26/Oct/2015:17:16:57 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.23.234.158 - - [26/Oct/2015:17:17:30 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:17:17:32 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:17:17:33 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:17:17:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:17:17:36 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.234.158 - - [26/Oct/2015:17:17:37 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.55.104.205 - - [26/Oct/2015:17:18:27 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.55.104.205 - - [26/Oct/2015:17:18:28 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.55.104.205 - - [26/Oct/2015:17:18:29 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.55.104.205 - - [26/Oct/2015:17:18:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.227.222.207 - - [26/Oct/2015:17:23:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.227.222.207 - - [26/Oct/2015:17:23:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.254.249.15 - - [26/Oct/2015:17:50:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 173.254.249.15 - - [26/Oct/2015:17:50:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.170.4 - - [26/Oct/2015:18:07:40 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.170.4 - - [26/Oct/2015:18:07:41 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.170.4 - - [26/Oct/2015:18:07:43 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.170.4 - - [26/Oct/2015:18:07:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.170.4 - - [26/Oct/2015:18:07:46 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.170.4 - - [26/Oct/2015:18:07:47 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.12.82.177 - - [26/Oct/2015:18:25:35 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.177 - - [26/Oct/2015:18:25:38 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.177 - - [26/Oct/2015:18:25:40 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.177 - - [26/Oct/2015:18:25:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.177 - - [26/Oct/2015:18:25:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.12.82.177 - - [26/Oct/2015:18:25:43 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 31.187.79.31 - - [26/Oct/2015:18:34:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 31.187.79.31 - - [26/Oct/2015:18:34:28 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 31.187.79.31 - - [26/Oct/2015:18:34:28 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 31.187.79.31 - - [26/Oct/2015:18:34:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 31.187.79.31 - - [26/Oct/2015:18:34:34 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 31.187.79.31 - - [26/Oct/2015:18:34:35 +0100] "POST /login_form HTTP/1.1" 200 18289 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 117.177.243.42 - - [26/Oct/2015:19:07:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 117.177.243.42 - - [26/Oct/2015:19:07:58 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 117.177.243.42 - - [26/Oct/2015:19:08:00 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 117.177.243.42 - - [26/Oct/2015:19:08:01 +0100] "POST /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 202.119.25.69 - - [26/Oct/2015:19:08:31 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 202.119.25.69 - - [26/Oct/2015:19:08:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 202.119.25.69 - - [26/Oct/2015:19:08:36 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 202.119.25.69 - - [26/Oct/2015:19:08:39 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 45.33.149.141 - - [26/Oct/2015:19:18:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 45.33.149.141 - - [26/Oct/2015:19:18:37 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 45.33.149.141 - - [26/Oct/2015:19:18:38 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.18.52 - - [26/Oct/2015:19:20:50 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.18.52 - - [26/Oct/2015:19:20:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.18.52 - - [26/Oct/2015:19:20:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.18.52 - - [26/Oct/2015:19:20:58 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.18.52 - - [26/Oct/2015:19:21:01 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.157.42.183 - - [26/Oct/2015:19:29:33 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.157.42.183 - - [26/Oct/2015:19:29:37 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.157.42.183 - - [26/Oct/2015:19:29:41 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.157.42.183 - - [26/Oct/2015:19:29:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.157.42.183 - - [26/Oct/2015:19:29:49 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 5.157.42.183 - - [26/Oct/2015:19:29:55 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 93.179.89.37 - - [26/Oct/2015:19:54:48 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 93.179.89.37 - - [26/Oct/2015:19:54:49 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 93.179.89.37 - - [26/Oct/2015:19:54:50 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 93.179.89.37 - - [26/Oct/2015:19:54:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 93.179.89.37 - - [26/Oct/2015:19:54:52 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 93.179.89.37 - - [26/Oct/2015:19:54:53 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.99.244.139 - - [26/Oct/2015:20:18:57 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.152.206.246 - - [26/Oct/2015:20:28:59 +0100] "GET /splittable-gzip HTTP/1.0" 200 27869 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.152.206.246 - - [26/Oct/2015:20:29:01 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.152.206.246 - - [26/Oct/2015:20:29:03 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.152.206.246 - - [26/Oct/2015:20:29:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.152.206.246 - - [26/Oct/2015:20:29:07 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 204.152.206.246 - - [26/Oct/2015:20:29:08 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 94.23.33.25 - - [26/Oct/2015:20:42:54 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.204 - - [26/Oct/2015:20:42:55 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.204 - - [26/Oct/2015:20:42:56 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.204 - - [26/Oct/2015:20:42:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.204 - - [26/Oct/2015:20:42:59 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 107.158.89.204 - - [26/Oct/2015:20:43:00 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.15.194 - - [26/Oct/2015:20:45:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 158.222.15.194 - - [26/Oct/2015:20:45:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 216.158.196.211 - - [26/Oct/2015:21:20:04 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 216.158.196.211 - - [26/Oct/2015:21:20:06 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 216.158.196.211 - - [26/Oct/2015:21:20:08 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 216.158.196.211 - - [26/Oct/2015:21:20:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 216.158.196.211 - - [26/Oct/2015:21:20:10 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 216.158.196.211 - - [26/Oct/2015:21:20:11 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 46.102.99.22 - - [26/Oct/2015:21:26:43 +0100] "GET /author/nielsbasjes HTTP/1.0" 200 15519 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 46.102.99.22 - - [26/Oct/2015:21:26:45 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 46.102.99.22 - - [26/Oct/2015:21:26:46 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 46.102.99.22 - - [26/Oct/2015:21:26:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 46.102.99.22 - - [26/Oct/2015:21:26:53 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 46.102.99.22 - - [26/Oct/2015:21:26:54 +0100] "POST /login_form HTTP/1.1" 200 18237 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 31.222.197.118 - - [26/Oct/2015:21:29:58 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.222.197.118 - - [26/Oct/2015:21:29:59 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.222.197.118 - - [26/Oct/2015:21:30:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.222.197.118 - - [26/Oct/2015:21:30:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 110.52.149.19 - - [26/Oct/2015:21:31:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 110.52.149.19 - - [26/Oct/2015:21:31:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.99.244.139 - - [26/Oct/2015:21:43:01 +0100] "GET /accessibility-info HTTP/1.1" 200 20622 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 172.245.229.166 - - [26/Oct/2015:22:53:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 172.245.229.166 - - [26/Oct/2015:22:53:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.99.244.139 - - [26/Oct/2015:22:54:34 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.72.156 - - [26/Oct/2015:23:10:58 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.72.156 - - [26/Oct/2015:23:11:02 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.72.156 - - [26/Oct/2015:23:11:04 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.72.156 - - [26/Oct/2015:23:11:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.72.156 - - [26/Oct/2015:23:11:08 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.72.156 - - [26/Oct/2015:23:11:10 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 183.120.167.25 - - [26/Oct/2015:23:29:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 183.120.167.25 - - [26/Oct/2015:23:29:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 183.120.167.25 - - [26/Oct/2015:23:29:28 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.69.206 - - [26/Oct/2015:23:50:07 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.69.206 - - [26/Oct/2015:23:50:11 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.69.206 - - [26/Oct/2015:23:50:12 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.69.206 - - [26/Oct/2015:23:50:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.69.206 - - [26/Oct/2015:23:50:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.69.206 - - [26/Oct/2015:23:50:19 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.99.244.139 - - [27/Oct/2015:00:05:51 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:00:28:37 +0100] "GET /linux/installing-my-new-server/voice-over-ip/RK=0/RS=tDIUMWhLOlRs5FUbKMPumYVN.f0- HTTP/1.1" 404 12146 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [27/Oct/2015:00:28:38 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/voice-over-ip/RK=0/RS=tDIUMWhLOlRs5FUbKMPumYVN.f0-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [27/Oct/2015:00:28:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [27/Oct/2015:00:28:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [27/Oct/2015:00:28:41 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 23.254.164.173 - - [27/Oct/2015:00:28:41 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31" 192.161.239.229 - - [27/Oct/2015:00:34:41 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.239.229 - - [27/Oct/2015:00:34:43 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.239.229 - - [27/Oct/2015:00:34:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.239.229 - - [27/Oct/2015:00:34:45 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.161.239.229 - - [27/Oct/2015:00:34:46 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.119.149.176 - - [27/Oct/2015:00:35:12 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.176 - - [27/Oct/2015:00:35:13 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.176 - - [27/Oct/2015:00:35:14 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.176 - - [27/Oct/2015:00:35:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.176 - - [27/Oct/2015:00:35:15 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 192.119.149.176 - - [27/Oct/2015:00:35:16 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 180.180.75.99 - - [27/Oct/2015:00:35:57 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.75.99 - - [27/Oct/2015:00:35:59 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.75.99 - - [27/Oct/2015:00:36:01 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.75.99 - - [27/Oct/2015:00:36:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.75.99 - - [27/Oct/2015:00:36:04 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.75.99 - - [27/Oct/2015:00:36:06 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.229.16 - - [27/Oct/2015:01:28:12 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.229.16 - - [27/Oct/2015:01:28:13 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.229.16 - - [27/Oct/2015:01:28:15 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.229.16 - - [27/Oct/2015:01:28:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:01:57:45 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:01:57:48 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:01:57:51 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:01:57:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:01:57:59 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:01:58:00 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.108.129.22 - - [27/Oct/2015:02:05:54 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.108.129.22 - - [27/Oct/2015:02:05:55 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.108.129.22 - - [27/Oct/2015:02:05:56 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.108.129.22 - - [27/Oct/2015:02:05:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.108.129.22 - - [27/Oct/2015:02:05:59 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.108.129.22 - - [27/Oct/2015:02:06:02 +0100] "POST /login_form HTTP/1.0" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 95.154.210.132 - - [27/Oct/2015:02:09:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 95.154.210.132 - - [27/Oct/2015:02:09:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.119.76 - - [27/Oct/2015:02:19:08 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.119.76 - - [27/Oct/2015:02:19:10 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.119.76 - - [27/Oct/2015:02:19:12 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.119.76 - - [27/Oct/2015:02:19:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.119.76 - - [27/Oct/2015:02:19:14 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.94.119.76 - - [27/Oct/2015:02:19:15 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [27/Oct/2015:03:03:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [27/Oct/2015:03:03:22 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [27/Oct/2015:03:03:22 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [27/Oct/2015:03:03:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [27/Oct/2015:03:03:24 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 62.210.204.180 - - [27/Oct/2015:03:03:24 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 45.33.146.8 - - [27/Oct/2015:03:14:22 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 45.33.146.8 - - [27/Oct/2015:03:14:23 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 45.33.146.8 - - [27/Oct/2015:03:14:25 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 45.33.146.8 - - [27/Oct/2015:03:14:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 45.33.146.8 - - [27/Oct/2015:03:14:29 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 45.33.146.8 - - [27/Oct/2015:03:14:31 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 89.35.104.119 - - [27/Oct/2015:03:28:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.35.104.119 - - [27/Oct/2015:03:28:43 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.35.104.119 - - [27/Oct/2015:03:28:45 +0100] "POST /login_form HTTP/1.1" 200 16854 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.114.7 - - [27/Oct/2015:03:29:24 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24367 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.114.7 - - [27/Oct/2015:03:29:27 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.114.7 - - [27/Oct/2015:03:29:30 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.114.7 - - [27/Oct/2015:03:29:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.114.7 - - [27/Oct/2015:03:29:33 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.114.7 - - [27/Oct/2015:03:29:34 +0100] "POST /login_form HTTP/1.1" 200 16854 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 188.210.215.242 - - [27/Oct/2015:03:37:26 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24367 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 188.210.215.242 - - [27/Oct/2015:03:37:27 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 188.210.215.242 - - [27/Oct/2015:03:37:28 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 188.210.215.242 - - [27/Oct/2015:03:37:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 66.150.34.157 - - [27/Oct/2015:04:04:04 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 66.150.34.157 - - [27/Oct/2015:04:04:06 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 66.150.34.157 - - [27/Oct/2015:04:04:07 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 66.150.34.157 - - [27/Oct/2015:04:04:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 66.150.34.157 - - [27/Oct/2015:04:04:08 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 66.150.34.157 - - [27/Oct/2015:04:04:09 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 23.231.24.17 - - [27/Oct/2015:04:17:31 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36488 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 23.231.24.17 - - [27/Oct/2015:04:17:33 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 23.231.24.17 - - [27/Oct/2015:04:17:34 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 23.231.24.17 - - [27/Oct/2015:04:17:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 23.231.24.17 - - [27/Oct/2015:04:17:36 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 23.231.24.17 - - [27/Oct/2015:04:17:37 +0100] "POST /login_form HTTP/1.1" 200 16854 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko" 198.23.234.158 - - [27/Oct/2015:04:45:56 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.234.158 - - [27/Oct/2015:04:45:58 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.234.158 - - [27/Oct/2015:04:46:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.234.158 - - [27/Oct/2015:04:46:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.234.158 - - [27/Oct/2015:04:46:03 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.234.158 - - [27/Oct/2015:04:46:05 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.209 - - [27/Oct/2015:04:47:00 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.209 - - [27/Oct/2015:04:47:01 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.209 - - [27/Oct/2015:04:47:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.209 - - [27/Oct/2015:04:47:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.209 - - [27/Oct/2015:04:47:05 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.209 - - [27/Oct/2015:04:47:06 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:04:51:34 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:04:51:35 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:04:51:35 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:04:51:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:04:51:36 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:04:51:37 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.99.244.139 - - [27/Oct/2015:05:06:32 +0100] "GET /accessibility-info HTTP/1.1" 200 20622 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.99.244.139 - - [27/Oct/2015:05:06:33 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.99.244.139 - - [27/Oct/2015:05:06:34 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.99.244.139 - - [27/Oct/2015:05:06:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.99.244.139 - - [27/Oct/2015:05:06:36 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.99.244.139 - - [27/Oct/2015:05:06:36 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.3.193.93 - - [27/Oct/2015:05:28:18 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.3.193.93 - - [27/Oct/2015:05:28:20 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.3.193.93 - - [27/Oct/2015:05:28:21 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.3.193.93 - - [27/Oct/2015:05:28:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.9.148 - - [27/Oct/2015:05:28:23 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.9.148 - - [27/Oct/2015:05:28:24 +0100] "GET /search?SearchableText= HTTP/1.1" 200 10773 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.9.148 - - [27/Oct/2015:05:28:26 +0100] "GET /login_form HTTP/1.1" 200 11642 "http://niels.basjes.nl/search?SearchableText=" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.9.148 - - [27/Oct/2015:05:28:27 +0100] "POST /login_form HTTP/1.1" 200 18372 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:05:32:31 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:05:32:32 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:05:32:33 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:05:32:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:05:32:34 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 31.220.113.224 - - [27/Oct/2015:05:32:34 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 188.210.215.223 - - [27/Oct/2015:05:37:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 188.210.215.223 - - [27/Oct/2015:05:37:25 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 188.210.215.223 - - [27/Oct/2015:05:37:25 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 165.231.27.136 - - [27/Oct/2015:05:46:23 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19418 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 165.231.27.136 - - [27/Oct/2015:05:46:24 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 165.231.27.136 - - [27/Oct/2015:05:46:25 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 165.231.27.136 - - [27/Oct/2015:05:46:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 165.231.27.136 - - [27/Oct/2015:05:46:27 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 165.231.27.136 - - [27/Oct/2015:05:46:28 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:05:48:07 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:05:48:10 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:05:48:12 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:05:48:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:05:48:19 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.109.46 - - [27/Oct/2015:05:48:20 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.254.119.236 - - [27/Oct/2015:05:57:18 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.236 - - [27/Oct/2015:05:57:20 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.236 - - [27/Oct/2015:05:57:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.236 - - [27/Oct/2015:05:57:21 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.236 - - [27/Oct/2015:05:57:22 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 50.31.9.98 - - [27/Oct/2015:06:02:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 50.31.9.98 - - [27/Oct/2015:06:02:48 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.239 - - [27/Oct/2015:06:02:54 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.239 - - [27/Oct/2015:06:03:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 199.195.158.63 - - [27/Oct/2015:06:23:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 199.195.158.63 - - [27/Oct/2015:06:23:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.99.74 - - [27/Oct/2015:06:27:02 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.99.74 - - [27/Oct/2015:06:27:04 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.99.74 - - [27/Oct/2015:06:27:05 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.99.74 - - [27/Oct/2015:06:27:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.99.74 - - [27/Oct/2015:06:27:08 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.99.74 - - [27/Oct/2015:06:27:10 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.66.139 - - [27/Oct/2015:06:32:38 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.0" 200 25005 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.12.66.139 - - [27/Oct/2015:06:32:40 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.12.66.139 - - [27/Oct/2015:06:32:41 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.12.66.139 - - [27/Oct/2015:06:32:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.12.66.139 - - [27/Oct/2015:06:32:48 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.12.66.139 - - [27/Oct/2015:06:32:54 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.19.69 - - [27/Oct/2015:06:33:52 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.19.69 - - [27/Oct/2015:06:33:54 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.19.69 - - [27/Oct/2015:06:33:56 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.19.69 - - [27/Oct/2015:06:33:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.19.69 - - [27/Oct/2015:06:33:59 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.144.19.69 - - [27/Oct/2015:06:34:01 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 192.99.244.139 - - [27/Oct/2015:06:36:55 +0100] "GET /accessibility-info HTTP/1.1" 200 20622 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.15.195 - - [27/Oct/2015:06:39:17 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.15.195 - - [27/Oct/2015:06:39:18 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.15.195 - - [27/Oct/2015:06:39:19 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.15.195 - - [27/Oct/2015:06:39:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.15.195 - - [27/Oct/2015:06:39:21 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.15.195 - - [27/Oct/2015:06:39:22 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 61.75.2.124 - - [27/Oct/2015:06:48:48 +0100] "GET / HTTP/1.0" 200 17053 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 61.75.2.124 - - [27/Oct/2015:06:49:04 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 61.75.2.124 - - [27/Oct/2015:06:49:17 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 61.75.2.124 - - [27/Oct/2015:06:49:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 61.75.2.124 - - [27/Oct/2015:06:49:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 61.75.2.124 - - [27/Oct/2015:06:49:54 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.254.119.252 - - [27/Oct/2015:06:50:32 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.252 - - [27/Oct/2015:06:50:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.252 - - [27/Oct/2015:06:50:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.252 - - [27/Oct/2015:06:50:35 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 155.254.119.252 - - [27/Oct/2015:06:50:36 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.158.188 - - [27/Oct/2015:06:52:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.158.188 - - [27/Oct/2015:06:52:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.247.182.225 - - [27/Oct/2015:07:14:26 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.247.182.225 - - [27/Oct/2015:07:14:27 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.247.182.225 - - [27/Oct/2015:07:14:28 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.247.182.225 - - [27/Oct/2015:07:14:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.247.182.225 - - [27/Oct/2015:07:14:30 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 23.247.182.225 - - [27/Oct/2015:07:14:30 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 198.23.158.188 - - [27/Oct/2015:07:19:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.158.188 - - [27/Oct/2015:07:19:26 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.158.188 - - [27/Oct/2015:07:19:27 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.23.158.188 - - [27/Oct/2015:07:19:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.103.125 - - [27/Oct/2015:07:19:40 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.103.125 - - [27/Oct/2015:07:19:42 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.103.125 - - [27/Oct/2015:07:19:43 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.103.125 - - [27/Oct/2015:07:19:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.103.125 - - [27/Oct/2015:07:19:46 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.103.125 - - [27/Oct/2015:07:19:47 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.254.212.109 - - [27/Oct/2015:07:40:07 +0100] "GET /splittable-gzip HTTP/1.1" 200 27869 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [27/Oct/2015:07:40:09 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [27/Oct/2015:07:40:10 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [27/Oct/2015:07:40:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [27/Oct/2015:07:40:12 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 104.254.212.109 - - [27/Oct/2015:07:40:13 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.0; rv:34.0) Gecko/20100101 Firefox/34.0" 50.31.9.73 - - [27/Oct/2015:08:04:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 50.31.9.215 - - [27/Oct/2015:08:04:47 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 50.31.9.73 - - [27/Oct/2015:08:04:49 +0100] "POST /login_form HTTP/1.0" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 187.87.166.63 - - [27/Oct/2015:08:14:59 +0100] "GET /places HTTP/1.1" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 187.87.166.63 - - [27/Oct/2015:08:15:18 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 14.72.24.3 - - [27/Oct/2015:08:15:37 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 14.72.24.3 - - [27/Oct/2015:08:15:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 14.72.24.3 - - [27/Oct/2015:08:15:42 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 14.72.24.3 - - [27/Oct/2015:08:15:44 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.247.140.245 - - [27/Oct/2015:08:30:05 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.168.10.150 - - [27/Oct/2015:08:30:07 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.168.10.150 - - [27/Oct/2015:08:30:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.168.10.150 - - [27/Oct/2015:08:30:10 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.168.10.150 - - [27/Oct/2015:08:30:13 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [27/Oct/2015:08:34:02 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [27/Oct/2015:08:34:04 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [27/Oct/2015:08:34:05 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [27/Oct/2015:08:34:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [27/Oct/2015:08:34:10 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [27/Oct/2015:08:34:11 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.82.177 - - [27/Oct/2015:08:47:11 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 198.12.82.177 - - [27/Oct/2015:08:47:13 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 198.12.82.177 - - [27/Oct/2015:08:47:15 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 198.12.82.177 - - [27/Oct/2015:08:47:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 198.12.82.177 - - [27/Oct/2015:08:47:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 198.12.82.177 - - [27/Oct/2015:08:47:18 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 216.158.196.24 - - [27/Oct/2015:08:52:55 +0100] "GET /open-source HTTP/1.0" 200 17525 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.196.24 - - [27/Oct/2015:08:53:04 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.196.24 - - [27/Oct/2015:08:53:05 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.196.24 - - [27/Oct/2015:08:53:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.8.215 - - [27/Oct/2015:08:56:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.8.215 - - [27/Oct/2015:08:56:22 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.197.69 - - [27/Oct/2015:08:56:24 +0100] "POST /login_form HTTP/1.0" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 37.203.212.82 - - [27/Oct/2015:09:00:03 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 37.203.212.82 - - [27/Oct/2015:09:00:03 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 37.203.212.82 - - [27/Oct/2015:09:00:05 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 37.203.212.82 - - [27/Oct/2015:09:00:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.106.192.53 - - [27/Oct/2015:09:18:28 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.106.192.53 - - [27/Oct/2015:09:18:30 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.106.192.53 - - [27/Oct/2015:09:18:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.106.192.53 - - [27/Oct/2015:09:18:34 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.106.192.53 - - [27/Oct/2015:09:18:36 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.210.223.92 - - [27/Oct/2015:09:21:04 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.92 - - [27/Oct/2015:09:21:06 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.92 - - [27/Oct/2015:09:21:08 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.92 - - [27/Oct/2015:09:21:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.92 - - [27/Oct/2015:09:21:10 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.92 - - [27/Oct/2015:09:21:11 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 5.157.10.116 - - [27/Oct/2015:09:41:03 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19418 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.10.116 - - [27/Oct/2015:09:41:04 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.10.116 - - [27/Oct/2015:09:41:05 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.10.116 - - [27/Oct/2015:09:41:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.10.116 - - [27/Oct/2015:09:41:06 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.10.116 - - [27/Oct/2015:09:41:07 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.152 - - [27/Oct/2015:09:45:59 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.152 - - [27/Oct/2015:09:46:01 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.152 - - [27/Oct/2015:09:46:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.152 - - [27/Oct/2015:09:46:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.152 - - [27/Oct/2015:09:46:04 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.80.152 - - [27/Oct/2015:09:46:06 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.161.83.180 - - [27/Oct/2015:09:46:29 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.161.83.180 - - [27/Oct/2015:09:46:31 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.161.83.180 - - [27/Oct/2015:09:46:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.161.83.180 - - [27/Oct/2015:09:46:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.161.83.180 - - [27/Oct/2015:09:46:35 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.161.83.180 - - [27/Oct/2015:09:46:36 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.161.195.201 - - [27/Oct/2015:09:55:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.195.201 - - [27/Oct/2015:09:55:07 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.195.201 - - [27/Oct/2015:09:55:08 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.119.26 - - [27/Oct/2015:09:55:51 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.119.26 - - [27/Oct/2015:09:55:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.119.26 - - [27/Oct/2015:09:55:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.119.26 - - [27/Oct/2015:09:55:54 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 172.245.119.26 - - [27/Oct/2015:09:55:56 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.126.192.60 - - [27/Oct/2015:10:16:11 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.126.192.60 - - [27/Oct/2015:10:16:13 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.126.192.60 - - [27/Oct/2015:10:16:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.126.192.60 - - [27/Oct/2015:10:16:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.126.192.60 - - [27/Oct/2015:10:16:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.126.192.60 - - [27/Oct/2015:10:16:19 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:10:16:56 +0100] "GET /linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE- HTTP/1.1" 404 12145 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:10:16:57 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:10:16:57 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:10:16:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:10:16:59 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:10:17:00 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.95.236.173 - - [27/Oct/2015:10:27:49 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.236.173 - - [27/Oct/2015:10:27:51 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.236.173 - - [27/Oct/2015:10:27:53 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.236.173 - - [27/Oct/2015:10:27:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.236.173 - - [27/Oct/2015:10:27:58 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.236.173 - - [27/Oct/2015:10:28:00 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.177.173 - - [27/Oct/2015:10:57:28 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.0" 200 25005 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.177.173 - - [27/Oct/2015:10:57:30 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.177.173 - - [27/Oct/2015:10:57:30 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.177.173 - - [27/Oct/2015:10:57:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.177.173 - - [27/Oct/2015:10:57:32 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.177.173 - - [27/Oct/2015:10:57:33 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 94.242.246.238 - - [27/Oct/2015:11:00:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 94.242.246.238 - - [27/Oct/2015:11:00:24 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 94.242.246.238 - - [27/Oct/2015:11:00:24 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.171.34 - - [27/Oct/2015:11:13:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//facebookhacktips.weebly.com HTTP/1.0" 200 10664 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.171.34 - - [27/Oct/2015:11:13:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//facebookhacktips.weebly.com" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.171.34 - - [27/Oct/2015:11:13:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.255.77.234 - - [27/Oct/2015:11:25:09 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.255.77.234 - - [27/Oct/2015:11:25:10 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.255.77.234 - - [27/Oct/2015:11:25:12 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.255.77.234 - - [27/Oct/2015:11:25:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.255.77.234 - - [27/Oct/2015:11:25:15 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.255.77.234 - - [27/Oct/2015:11:25:16 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.66.187 - - [27/Oct/2015:11:42:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.66.187 - - [27/Oct/2015:11:42:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.247.182.75 - - [27/Oct/2015:11:59:12 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.247.182.75 - - [27/Oct/2015:11:59:13 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.247.182.75 - - [27/Oct/2015:11:59:14 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 148.251.65.34 - - [27/Oct/2015:12:20:59 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:21:01 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:21:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:21:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:21:04 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:21:06 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 148.251.65.34 - - [27/Oct/2015:12:22:53 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:22:55 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:22:56 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:22:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:22:58 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.119.144.246 - - [27/Oct/2015:12:22:59 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.139 - - [27/Oct/2015:12:26:59 +0100] "GET /open-source HTTP/1.0" 200 17525 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.139 - - [27/Oct/2015:12:27:01 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.139 - - [27/Oct/2015:12:27:03 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.139 - - [27/Oct/2015:12:27:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.200.122 - - [27/Oct/2015:12:30:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.200.122 - - [27/Oct/2015:12:30:58 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.200.122 - - [27/Oct/2015:12:31:01 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 178.216.54.249 - - [27/Oct/2015:13:00:58 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 178.216.54.249 - - [27/Oct/2015:13:00:59 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 178.216.54.249 - - [27/Oct/2015:13:01:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 178.216.54.249 - - [27/Oct/2015:13:01:02 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 178.216.54.249 - - [27/Oct/2015:13:01:03 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 94.242.246.233 - - [27/Oct/2015:13:02:19 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 94.242.246.233 - - [27/Oct/2015:13:02:19 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.239 - - [27/Oct/2015:13:07:58 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.239 - - [27/Oct/2015:13:08:16 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.239 - - [27/Oct/2015:13:08:27 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.239 - - [27/Oct/2015:13:08:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.181.217 - - [27/Oct/2015:13:12:02 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.181.217 - - [27/Oct/2015:13:12:03 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.181.217 - - [27/Oct/2015:13:12:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.181.217 - - [27/Oct/2015:13:12:06 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.95.181.217 - - [27/Oct/2015:13:12:07 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:13:17:33 +0100] "GET /linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8- HTTP/1.1" 404 12146 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:13:17:34 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:13:17:35 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:13:17:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:13:17:37 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:13:17:38 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 192.210.223.69 - - [27/Oct/2015:13:22:55 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.69 - - [27/Oct/2015:13:22:58 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.69 - - [27/Oct/2015:13:22:59 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.69 - - [27/Oct/2015:13:23:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.69 - - [27/Oct/2015:13:23:01 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.210.223.69 - - [27/Oct/2015:13:23:02 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 50.2.190.172 - - [27/Oct/2015:14:12:02 +0100] "GET /splittable-gzip HTTP/1.0" 200 27760 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 50.2.190.172 - - [27/Oct/2015:14:12:04 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 50.2.190.172 - - [27/Oct/2015:14:12:05 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 50.2.190.172 - - [27/Oct/2015:14:12:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 50.2.190.172 - - [27/Oct/2015:14:12:08 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 50.2.190.172 - - [27/Oct/2015:14:12:10 +0100] "POST /login_form HTTP/1.1" 200 18237 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 50.31.9.98 - - [27/Oct/2015:14:26:24 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 50.31.9.73 - - [27/Oct/2015:14:26:28 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 50.31.9.98 - - [27/Oct/2015:14:26:32 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.144.182.240 - - [27/Oct/2015:14:26:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//socialnetworksafety.edublogs.org HTTP/1.0" 200 10674 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.144.182.240 - - [27/Oct/2015:14:27:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//socialnetworksafety.edublogs.org" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.144.182.240 - - [27/Oct/2015:14:27:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.172 - - [27/Oct/2015:15:04:19 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.172 - - [27/Oct/2015:15:04:24 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.172 - - [27/Oct/2015:15:04:26 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.172 - - [27/Oct/2015:15:04:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.140.99 - - [27/Oct/2015:15:04:30 +0100] "GET /login_form HTTP/1.0" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.140.99 - - [27/Oct/2015:15:04:39 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.222 - - [27/Oct/2015:15:19:02 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.222 - - [27/Oct/2015:15:19:03 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.222 - - [27/Oct/2015:15:19:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.222 - - [27/Oct/2015:15:19:05 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.222 - - [27/Oct/2015:15:19:06 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 196.196.20.88 - - [27/Oct/2015:15:21:23 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 196.196.20.88 - - [27/Oct/2015:15:21:24 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 196.196.20.88 - - [27/Oct/2015:15:21:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.117.183 - - [27/Oct/2015:15:21:26 +0100] "GET /login_form HTTP/1.0" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.117.183 - - [27/Oct/2015:15:21:27 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.117.183 - - [27/Oct/2015:15:24:03 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.117.183 - - [27/Oct/2015:15:24:04 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.117.183 - - [27/Oct/2015:15:24:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.117.183 - - [27/Oct/2015:15:24:07 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.12.117.183 - - [27/Oct/2015:15:24:09 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:15:24:28 +0100] "GET /linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8- HTTP/1.1" 404 12146 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:15:24:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:15:24:30 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:15:24:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:15:24:33 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:15:24:34 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 162.253.53.42 - - [27/Oct/2015:15:31:35 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.42 - - [27/Oct/2015:15:31:39 +0100] "GET /join_form HTTP/1.1" 200 11114 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.42 - - [27/Oct/2015:15:31:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.42 - - [27/Oct/2015:15:31:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.42 - - [27/Oct/2015:15:31:41 +0100] "GET /login_form HTTP/1.1" 200 10505 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.42 - - [27/Oct/2015:15:31:41 +0100] "POST /login_form HTTP/1.1" 200 16768 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.152 - - [27/Oct/2015:15:47:35 +0100] "GET /author/nielsbasjes HTTP/1.0" 200 15519 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 31.187.79.152 - - [27/Oct/2015:15:47:35 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 31.187.79.152 - - [27/Oct/2015:15:47:36 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 31.187.79.152 - - [27/Oct/2015:15:47:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 31.187.79.152 - - [27/Oct/2015:15:47:37 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 31.187.79.152 - - [27/Oct/2015:15:47:38 +0100] "POST /login_form HTTP/1.1" 200 18237 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 69.12.79.119 - - [27/Oct/2015:15:55:49 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 69.12.79.119 - - [27/Oct/2015:15:55:50 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 69.12.79.119 - - [27/Oct/2015:15:55:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 69.12.79.119 - - [27/Oct/2015:15:55:53 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 69.12.79.119 - - [27/Oct/2015:15:55:55 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.142 - - [27/Oct/2015:15:56:30 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.142 - - [27/Oct/2015:15:56:31 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.142 - - [27/Oct/2015:15:56:32 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.142 - - [27/Oct/2015:15:56:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.142 - - [27/Oct/2015:15:56:34 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.142 - - [27/Oct/2015:15:56:35 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 94.242.212.19 - - [27/Oct/2015:16:10:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.212.19 - - [27/Oct/2015:16:10:57 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.212.19 - - [27/Oct/2015:16:11:01 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.212.19 - - [27/Oct/2015:16:11:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.212.19 - - [27/Oct/2015:16:11:02 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.212.19 - - [27/Oct/2015:16:11:03 +0100] "POST /login_form HTTP/1.1" 200 18237 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 155.94.168.77 - - [27/Oct/2015:16:11:36 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.168.77 - - [27/Oct/2015:16:12:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.168.77 - - [27/Oct/2015:16:12:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.168.77 - - [27/Oct/2015:16:12:28 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.168.77 - - [27/Oct/2015:16:12:41 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 185.75.57.58 - - [27/Oct/2015:16:24:19 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 185.75.57.58 - - [27/Oct/2015:16:24:20 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 185.75.57.58 - - [27/Oct/2015:16:24:22 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 185.75.57.58 - - [27/Oct/2015:16:24:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 185.75.57.58 - - [27/Oct/2015:16:24:25 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 185.75.57.58 - - [27/Oct/2015:16:24:26 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 50.31.9.215 - - [27/Oct/2015:16:40:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 50.31.9.73 - - [27/Oct/2015:16:40:07 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 69.163.47.119 - - [27/Oct/2015:16:40:55 +0100] "GET /places HTTP/1.1" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 190.63.175.247 - - [27/Oct/2015:16:41:01 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:16:41:37 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:16:41:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:16:41:45 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:16:41:51 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.42.183 - - [27/Oct/2015:16:51:06 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.42.183 - - [27/Oct/2015:16:51:07 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.42.183 - - [27/Oct/2015:16:51:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.42.183 - - [27/Oct/2015:16:51:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.42.183 - - [27/Oct/2015:16:51:08 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.157.42.183 - - [27/Oct/2015:16:51:09 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.178 - - [27/Oct/2015:16:57:12 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.178 - - [27/Oct/2015:16:57:13 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.178 - - [27/Oct/2015:16:57:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.178 - - [27/Oct/2015:16:57:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.178 - - [27/Oct/2015:16:57:16 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.161.239.178 - - [27/Oct/2015:16:57:17 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.158.89.173 - - [27/Oct/2015:17:09:34 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.158.89.173 - - [27/Oct/2015:17:09:35 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.158.89.173 - - [27/Oct/2015:17:09:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.158.89.173 - - [27/Oct/2015:17:09:38 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.158.89.173 - - [27/Oct/2015:17:09:39 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:17:30:16 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:17:30:18 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:17:30:20 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:17:30:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:17:30:22 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:17:30:23 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 104.227.66.81 - - [27/Oct/2015:17:30:58 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.66.81 - - [27/Oct/2015:17:31:00 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.66.81 - - [27/Oct/2015:17:31:01 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.66.81 - - [27/Oct/2015:17:31:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.66.81 - - [27/Oct/2015:17:31:03 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.66.81 - - [27/Oct/2015:17:31:04 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.232.116.137 - - [27/Oct/2015:17:59:28 +0100] "GET /join_form HTTP/1.0" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 173.232.116.137 - - [27/Oct/2015:17:59:30 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 173.232.116.137 - - [27/Oct/2015:17:59:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 94.242.208.187 - - [27/Oct/2015:18:05:29 +0100] "GET /sitemap HTTP/1.0" 200 11975 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.208.187 - - [27/Oct/2015:18:05:31 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.208.187 - - [27/Oct/2015:18:05:31 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.208.187 - - [27/Oct/2015:18:05:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.208.187 - - [27/Oct/2015:18:05:33 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 94.242.208.187 - - [27/Oct/2015:18:05:35 +0100] "POST /login_form HTTP/1.1" 200 18237 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5" 23.236.210.83 - - [27/Oct/2015:18:26:45 +0100] "GET /splittable-gzip HTTP/1.0" 200 27869 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.236.210.83 - - [27/Oct/2015:18:26:46 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.236.210.83 - - [27/Oct/2015:18:26:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.233 - - [27/Oct/2015:18:48:56 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.233 - - [27/Oct/2015:18:48:58 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.233 - - [27/Oct/2015:18:49:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.233 - - [27/Oct/2015:18:49:03 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 170.130.59.233 - - [27/Oct/2015:18:49:07 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:18:51:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:18:51:56 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:18:51:58 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 218.200.66.196 - - [27/Oct/2015:18:52:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 121.204.74.138 - - [27/Oct/2015:18:57:10 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 121.204.74.138 - - [27/Oct/2015:18:57:15 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 121.204.74.138 - - [27/Oct/2015:18:57:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 107.172.0.248 - - [27/Oct/2015:18:59:50 +0100] "GET /places HTTP/1.0" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.0.248 - - [27/Oct/2015:18:59:52 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.0.248 - - [27/Oct/2015:18:59:53 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.0.248 - - [27/Oct/2015:18:59:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.0.248 - - [27/Oct/2015:18:59:55 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.172.0.248 - - [27/Oct/2015:18:59:57 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:19:03:35 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24319 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:19:03:37 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:19:03:38 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:19:03:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:19:03:39 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.113.224 - - [27/Oct/2015:19:03:40 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.136 - - [27/Oct/2015:19:04:30 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.136 - - [27/Oct/2015:19:04:31 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.136 - - [27/Oct/2015:19:04:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.136 - - [27/Oct/2015:19:04:32 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.136 - - [27/Oct/2015:19:04:33 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.236.195 - - [27/Oct/2015:19:16:58 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.236.195 - - [27/Oct/2015:19:16:59 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.236.195 - - [27/Oct/2015:19:17:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.236.195 - - [27/Oct/2015:19:17:02 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.236.195 - - [27/Oct/2015:19:17:03 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.52.158.252 - - [27/Oct/2015:19:23:18 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.52.158.252 - - [27/Oct/2015:19:23:19 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.52.158.252 - - [27/Oct/2015:19:23:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.52.158.252 - - [27/Oct/2015:19:23:22 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 198.52.158.252 - - [27/Oct/2015:19:23:24 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.246 - - [27/Oct/2015:19:30:28 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.246 - - [27/Oct/2015:19:30:28 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.246 - - [27/Oct/2015:19:30:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.246 - - [27/Oct/2015:19:30:30 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.32.251.246 - - [27/Oct/2015:19:30:31 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 123.88.10.57 - - [27/Oct/2015:19:40:41 +0100] "GET /places HTTP/1.1" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 123.88.10.57 - - [27/Oct/2015:19:41:17 +0100] "GET /places HTTP/1.1" 200 19355 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 123.88.10.57 - - [27/Oct/2015:19:41:20 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 123.88.10.57 - - [27/Oct/2015:19:41:25 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 123.88.10.57 - - [27/Oct/2015:19:41:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 123.88.10.57 - - [27/Oct/2015:19:41:28 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 123.88.10.57 - - [27/Oct/2015:19:42:03 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 41.109.52.32 - - [27/Oct/2015:20:02:35 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 41.109.52.32 - - [27/Oct/2015:20:02:54 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 41.109.52.32 - - [27/Oct/2015:20:03:01 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.72.96.104 - - [27/Oct/2015:20:06:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.72.96.104 - - [27/Oct/2015:20:06:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 66.150.34.163 - - [27/Oct/2015:20:10:06 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 66.150.34.163 - - [27/Oct/2015:20:10:08 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 66.150.34.163 - - [27/Oct/2015:20:10:09 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 66.150.34.163 - - [27/Oct/2015:20:10:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 66.150.34.163 - - [27/Oct/2015:20:10:10 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 66.150.34.163 - - [27/Oct/2015:20:10:11 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 187.141.230.35 - - [27/Oct/2015:20:23:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 187.141.230.35 - - [27/Oct/2015:20:23:28 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 187.141.230.35 - - [27/Oct/2015:20:23:33 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 187.141.230.35 - - [27/Oct/2015:20:23:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.229.229.178 - - [27/Oct/2015:20:24:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.229.229.178 - - [27/Oct/2015:20:24:21 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.229.229.178 - - [27/Oct/2015:20:24:22 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.229.229.178 - - [27/Oct/2015:20:24:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 190.82.115.159 - - [27/Oct/2015:20:30:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 190.82.115.159 - - [27/Oct/2015:20:30:25 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 190.82.115.159 - - [27/Oct/2015:20:30:36 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 190.82.115.159 - - [27/Oct/2015:20:30:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.168.85.254 - - [27/Oct/2015:20:34:44 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.168.85.254 - - [27/Oct/2015:20:34:45 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.168.85.254 - - [27/Oct/2015:20:34:49 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.168.85.254 - - [27/Oct/2015:20:34:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.168.85.254 - - [27/Oct/2015:20:34:53 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.168.85.254 - - [27/Oct/2015:20:34:54 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 69.163.47.119 - - [27/Oct/2015:21:31:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 112.14.108.18 - - [27/Oct/2015:21:31:51 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 112.14.108.18 - - [27/Oct/2015:21:32:35 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 183.207.228.40 - - [27/Oct/2015:21:32:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 183.207.228.38 - - [27/Oct/2015:21:32:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 190.63.175.247 - - [27/Oct/2015:21:32:56 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 117.177.243.42 - - [27/Oct/2015:21:33:11 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.83.183.34 - - [27/Oct/2015:21:54:57 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.83.183.34 - - [27/Oct/2015:21:54:58 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.83.183.34 - - [27/Oct/2015:21:54:59 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.83.183.34 - - [27/Oct/2015:21:54:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.83.183.34 - - [27/Oct/2015:21:54:59 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 212.83.183.34 - - [27/Oct/2015:21:55:00 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.250.67.105 - - [27/Oct/2015:22:14:16 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27448 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.250.67.105 - - [27/Oct/2015:22:14:17 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.250.67.105 - - [27/Oct/2015:22:14:18 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.250.67.105 - - [27/Oct/2015:22:14:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.250.67.105 - - [27/Oct/2015:22:14:21 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.250.67.105 - - [27/Oct/2015:22:14:22 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 91.238.82.193 - - [27/Oct/2015:22:23:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.238.82.193 - - [27/Oct/2015:22:23:39 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.238.82.193 - - [27/Oct/2015:22:23:40 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.161.57.137 - - [27/Oct/2015:22:24:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.161.57.137 - - [27/Oct/2015:22:24:41 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 37.230.212.151 - - [27/Oct/2015:22:30:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 37.230.212.151 - - [27/Oct/2015:22:30:31 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.223.44.38 - - [27/Oct/2015:22:31:08 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.223.44.38 - - [27/Oct/2015:22:31:11 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.223.44.38 - - [27/Oct/2015:22:31:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.223.44.38 - - [27/Oct/2015:22:31:15 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.223.44.38 - - [27/Oct/2015:22:31:17 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.207.67.234 - - [27/Oct/2015:22:52:09 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.207.67.234 - - [27/Oct/2015:22:52:11 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.10.179 - - [27/Oct/2015:23:05:28 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.10.179 - - [27/Oct/2015:23:05:29 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.10.179 - - [27/Oct/2015:23:05:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.10.179 - - [27/Oct/2015:23:05:30 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:23:07:16 +0100] "GET /linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE- HTTP/1.1" 404 12145 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:23:07:17 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/Various-software/RK=0/RS=C_oF6PJOAKvJ3JsgiwAbhNKI2uE-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:23:07:18 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:23:07:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:23:07:20 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 23.254.164.173 - - [27/Oct/2015:23:07:21 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.110 Safari/537.36" 88.150.210.124 - - [27/Oct/2015:23:21:56 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 88.150.210.124 - - [27/Oct/2015:23:21:56 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 88.150.210.124 - - [27/Oct/2015:23:21:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 88.150.210.124 - - [27/Oct/2015:23:21:57 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 88.150.210.124 - - [27/Oct/2015:23:21:57 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.198 - - [27/Oct/2015:23:35:27 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.198 - - [27/Oct/2015:23:35:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.198 - - [27/Oct/2015:23:35:29 +0100] "POST /join_form HTTP/1.1" 302 9245 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.198 - - [27/Oct/2015:23:35:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.198 - - [27/Oct/2015:23:35:31 +0100] "GET /login_form HTTP/1.1" 200 10505 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 162.253.53.198 - - [27/Oct/2015:23:35:31 +0100] "POST /login_form HTTP/1.1" 200 16768 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.3.106.205 - - [27/Oct/2015:23:47:23 +0100] "GET / HTTP/1.1" 200 20474 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.3.106.205 - - [27/Oct/2015:23:47:25 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.3.106.205 - - [27/Oct/2015:23:47:26 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.3.106.205 - - [27/Oct/2015:23:47:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.3.106.205 - - [27/Oct/2015:23:47:27 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 192.3.106.205 - - [27/Oct/2015:23:47:28 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:23:48:01 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36440 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:23:48:02 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:23:48:04 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:23:48:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:23:48:06 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.39 - - [27/Oct/2015:23:48:07 +0100] "POST /login_form HTTP/1.1" 200 16806 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:01:53 +0100] "GET / HTTP/1.0" 200 20474 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:01:54 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:01:54 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:01:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:01:55 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:01:56 +0100] "POST /login_form HTTP/1.1" 200 18350 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.65.53 - - [28/Oct/2015:00:10:49 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.65.53 - - [28/Oct/2015:00:10:50 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.65.53 - - [28/Oct/2015:00:10:52 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.65.53 - - [28/Oct/2015:00:10:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.65.53 - - [28/Oct/2015:00:10:54 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.36.65.53 - - [28/Oct/2015:00:10:55 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.94.170.4 - - [28/Oct/2015:00:29:46 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.170.4 - - [28/Oct/2015:00:29:48 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.170.4 - - [28/Oct/2015:00:29:49 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.170.4 - - [28/Oct/2015:00:29:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.170.4 - - [28/Oct/2015:00:29:51 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.170.4 - - [28/Oct/2015:00:29:52 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [28/Oct/2015:00:31:27 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:31:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:31:30 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:31:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:31:33 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:00:31:34 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.12.2 - - [28/Oct/2015:01:00:39 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.2 - - [28/Oct/2015:01:00:41 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.2 - - [28/Oct/2015:01:00:43 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.2 - - [28/Oct/2015:01:00:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.2 - - [28/Oct/2015:01:00:45 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 158.222.12.2 - - [28/Oct/2015:01:00:46 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 155.254.203.202 - - [28/Oct/2015:01:26:21 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.254.203.202 - - [28/Oct/2015:01:27:08 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.254.203.202 - - [28/Oct/2015:01:27:10 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.254.203.202 - - [28/Oct/2015:01:27:45 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.254.203.202 - - [28/Oct/2015:01:27:46 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.140.177 - - [28/Oct/2015:01:39:01 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.140.177 - - [28/Oct/2015:01:39:03 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.140.177 - - [28/Oct/2015:01:39:04 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.140.177 - - [28/Oct/2015:01:39:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.140.177 - - [28/Oct/2015:01:39:06 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 155.94.140.177 - - [28/Oct/2015:01:39:07 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.201.102 - - [28/Oct/2015:01:40:32 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.201.102 - - [28/Oct/2015:01:40:34 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.201.102 - - [28/Oct/2015:01:40:36 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.201.102 - - [28/Oct/2015:01:40:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.5.104 - - [28/Oct/2015:01:42:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.5.104 - - [28/Oct/2015:01:42:02 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.5.104 - - [28/Oct/2015:01:42:03 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.140.71.2 - - [28/Oct/2015:02:46:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.140.71.2 - - [28/Oct/2015:02:46:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 121.204.77.53 - - [28/Oct/2015:02:52:22 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.1" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 121.204.77.53 - - [28/Oct/2015:02:52:24 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 121.204.77.53 - - [28/Oct/2015:02:52:25 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 121.204.77.53 - - [28/Oct/2015:02:52:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 121.204.77.53 - - [28/Oct/2015:02:52:28 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 121.204.77.53 - - [28/Oct/2015:02:52:29 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.19.69 - - [28/Oct/2015:03:00:54 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [28/Oct/2015:03:00:55 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [28/Oct/2015:03:00:57 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [28/Oct/2015:03:00:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [28/Oct/2015:03:01:00 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.144.19.69 - - [28/Oct/2015:03:01:01 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:03:10:19 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:03:10:21 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:03:10:22 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:03:10:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:03:10:25 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:03:10:25 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:03:35:03 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:03:35:04 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:03:35:05 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:03:35:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:03:35:06 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:03:35:07 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.150.48.76 - - [28/Oct/2015:03:35:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.150.48.76 - - [28/Oct/2015:03:35:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.100.50.54 - - [28/Oct/2015:03:43:12 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0" 94.100.50.54 - - [28/Oct/2015:03:43:14 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0" 5.175.177.178 - - [28/Oct/2015:04:10:28 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19422 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 5.175.177.178 - - [28/Oct/2015:04:10:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 5.175.177.178 - - [28/Oct/2015:04:10:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.197.69 - - [28/Oct/2015:04:16:08 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.197.69 - - [28/Oct/2015:04:16:10 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.197.69 - - [28/Oct/2015:04:16:12 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.197.69 - - [28/Oct/2015:04:16:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 88.150.210.124 - - [28/Oct/2015:04:17:05 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 88.150.210.124 - - [28/Oct/2015:04:17:06 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.222 - - [28/Oct/2015:04:19:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.249 - - [28/Oct/2015:04:28:45 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.249 - - [28/Oct/2015:04:28:45 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.249 - - [28/Oct/2015:04:28:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.249 - - [28/Oct/2015:04:28:48 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.33.71.249 - - [28/Oct/2015:04:28:48 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:04:30:12 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:04:30:14 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:04:30:14 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:04:30:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:04:30:17 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.201 - - [28/Oct/2015:04:30:18 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:39:49 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:39:50 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:39:51 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:39:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:39:53 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:39:54 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.96.208 - - [28/Oct/2015:04:45:56 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.96.208 - - [28/Oct/2015:04:45:57 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.96.208 - - [28/Oct/2015:04:45:59 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.96.208 - - [28/Oct/2015:04:46:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.96.208 - - [28/Oct/2015:04:46:05 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.96.208 - - [28/Oct/2015:04:46:07 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 89.42.237.71 - - [28/Oct/2015:04:54:58 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:54:59 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:55:00 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:55:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:55:02 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 89.42.237.71 - - [28/Oct/2015:04:55:03 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.143.28.246 - - [28/Oct/2015:05:08:46 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.143.28.246 - - [28/Oct/2015:05:08:52 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.143.28.246 - - [28/Oct/2015:05:14:19 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.143.28.246 - - [28/Oct/2015:05:14:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.143.28.246 - - [28/Oct/2015:05:14:21 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.143.28.246 - - [28/Oct/2015:05:14:23 +0100] "POST /login_form HTTP/1.1" 200 16862 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.222 - - [28/Oct/2015:05:36:31 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.222 - - [28/Oct/2015:05:36:34 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.211.222 - - [28/Oct/2015:05:36:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:05:36:49 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24375 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:05:36:50 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:05:36:51 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:05:36:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:05:36:53 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.220.30.157 - - [28/Oct/2015:05:36:53 +0100] "POST /login_form HTTP/1.1" 200 16862 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.197.14 - - [28/Oct/2015:05:39:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.197.14 - - [28/Oct/2015:05:39:57 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.158.197.14 - - [28/Oct/2015:05:39:58 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 14.139.236.210 - - [28/Oct/2015:05:49:30 +0100] "GET /mail_password_form?userid= HTTP/1.0" 200 10820 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 14.139.236.210 - - [28/Oct/2015:05:49:34 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 14.139.236.210 - - [28/Oct/2015:05:49:37 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 14.139.236.210 - - [28/Oct/2015:05:49:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.200.24.243 - - [28/Oct/2015:06:18:25 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.200.24.243 - - [28/Oct/2015:06:18:28 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.200.24.243 - - [28/Oct/2015:06:18:29 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.200.24.243 - - [28/Oct/2015:06:18:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.200.24.243 - - [28/Oct/2015:06:18:32 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 192.200.24.243 - - [28/Oct/2015:06:18:33 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.223.44.139 - - [28/Oct/2015:06:19:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.223.44.139 - - [28/Oct/2015:06:19:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 186.27.126.130 - - [28/Oct/2015:06:28:27 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 186.27.126.130 - - [28/Oct/2015:06:29:07 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 186.27.126.130 - - [28/Oct/2015:06:29:10 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 186.27.126.130 - - [28/Oct/2015:06:29:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 186.27.126.130 - - [28/Oct/2015:06:29:15 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 186.27.126.130 - - [28/Oct/2015:06:29:17 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 107.158.113.117 - - [28/Oct/2015:06:59:04 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.158.113.117 - - [28/Oct/2015:06:59:05 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.158.113.117 - - [28/Oct/2015:06:59:07 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.158.113.117 - - [28/Oct/2015:06:59:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.158.113.117 - - [28/Oct/2015:06:59:10 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 107.158.113.117 - - [28/Oct/2015:06:59:12 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; CrOS x86_64 6310.68.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.96 Safari/537.36" 79.97.43.126 - - [28/Oct/2015:07:37:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:07:37:03 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:07:37:04 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.168.89.17 - - [28/Oct/2015:07:50:27 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.168.89.17 - - [28/Oct/2015:07:50:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 104.168.89.17 - - [28/Oct/2015:07:50:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 216.244.81.34 - - [28/Oct/2015:08:21:47 +0100] "GET / HTTP/1.1" 302 281 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:21:48 +0100] "GET / HTTP/1.1" 200 20478 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:21:49 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:21:50 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:21:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.67.82 - - [28/Oct/2015:08:29:45 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.67.82 - - [28/Oct/2015:08:29:48 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.67.82 - - [28/Oct/2015:08:29:50 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.67.82 - - [28/Oct/2015:08:29:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.67.82 - - [28/Oct/2015:08:29:55 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.67.82 - - [28/Oct/2015:08:29:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:37:36 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.1" 200 25009 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:37:38 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:37:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:08:37:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.250.33 - - [28/Oct/2015:08:43:59 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.250.33 - - [28/Oct/2015:08:44:01 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.250.33 - - [28/Oct/2015:08:44:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.250.33 - - [28/Oct/2015:08:44:04 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.250.33 - - [28/Oct/2015:08:44:05 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:08:46:29 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:08:46:29 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:08:46:30 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:08:46:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.33.159.106 - - [28/Oct/2015:09:10:32 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.106 - - [28/Oct/2015:09:10:34 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.106 - - [28/Oct/2015:09:10:36 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.106 - - [28/Oct/2015:09:10:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.106 - - [28/Oct/2015:09:10:39 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.106 - - [28/Oct/2015:09:10:40 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.141.10 - - [28/Oct/2015:09:38:03 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.141.10 - - [28/Oct/2015:09:38:13 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.141.10 - - [28/Oct/2015:09:38:17 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.169.2.11 - - [28/Oct/2015:09:48:43 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.169.2.11 - - [28/Oct/2015:09:48:45 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.169.2.11 - - [28/Oct/2015:09:48:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:10:23:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:10:23:11 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:10:23:12 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.149.114 - - [28/Oct/2015:10:23:35 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.149.114 - - [28/Oct/2015:10:23:39 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.149.114 - - [28/Oct/2015:10:23:42 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.149.114 - - [28/Oct/2015:10:23:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.149.114 - - [28/Oct/2015:10:23:46 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.149.114 - - [28/Oct/2015:10:23:48 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.12.82.174 - - [28/Oct/2015:10:40:45 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 198.12.82.174 - - [28/Oct/2015:10:40:47 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 198.12.82.174 - - [28/Oct/2015:10:40:48 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 198.12.82.174 - - [28/Oct/2015:10:40:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 198.12.82.174 - - [28/Oct/2015:10:40:50 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 198.12.82.174 - - [28/Oct/2015:10:40:51 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 185.104.217.140 - - [28/Oct/2015:10:41:08 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 185.104.217.140 - - [28/Oct/2015:10:41:10 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 185.104.217.140 - - [28/Oct/2015:10:41:11 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 185.104.217.140 - - [28/Oct/2015:10:41:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 185.104.217.140 - - [28/Oct/2015:10:41:14 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 185.104.217.140 - - [28/Oct/2015:10:41:15 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 119.73.118.1 - - [28/Oct/2015:10:42:04 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.73.118.1 - - [28/Oct/2015:10:42:05 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.73.118.1 - - [28/Oct/2015:10:42:06 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.73.118.1 - - [28/Oct/2015:10:42:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.73.118.1 - - [28/Oct/2015:10:42:08 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.73.118.1 - - [28/Oct/2015:10:42:09 +0100] "POST /login_form HTTP/1.0" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.5.104 - - [28/Oct/2015:10:45:49 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.5.104 - - [28/Oct/2015:10:45:51 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.5.104 - - [28/Oct/2015:10:45:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:10:46:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:10:46:32 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 79.97.43.126 - - [28/Oct/2015:10:46:32 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:10:59:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:10:59:44 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.244.81.34 - - [28/Oct/2015:10:59:45 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.92.78 - - [28/Oct/2015:11:00:53 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.0" 200 25009 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.92.78 - - [28/Oct/2015:11:00:54 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.92.78 - - [28/Oct/2015:11:00:55 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.92.78 - - [28/Oct/2015:11:00:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.227.92.78 - - [28/Oct/2015:11:00:58 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.100.158 - - [28/Oct/2015:11:05:23 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.158.100.158 - - [28/Oct/2015:11:05:24 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.158.100.158 - - [28/Oct/2015:11:05:25 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.158.100.158 - - [28/Oct/2015:11:05:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.158.100.158 - - [28/Oct/2015:11:05:27 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.158.100.158 - - [28/Oct/2015:11:05:28 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 94.23.33.25 - - [28/Oct/2015:11:22:56 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.221 - - [28/Oct/2015:11:22:57 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.68 - - [28/Oct/2015:11:22:59 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:11:25:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:25:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:11:29:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:29:12 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:29:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:29:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:29:16 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:29:18 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:11:32:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:32:25 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:32:27 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:32:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:32:29 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.44.112.144 - - [28/Oct/2015:11:32:31 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:11:38:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.131 - - [28/Oct/2015:11:38:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:11:44:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.152.206.187 - - [28/Oct/2015:11:44:39 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.152.206.187 - - [28/Oct/2015:11:44:41 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.152.206.187 - - [28/Oct/2015:11:44:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.152.206.187 - - [28/Oct/2015:11:44:44 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 204.152.206.187 - - [28/Oct/2015:11:44:45 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.72.9.89 - - [28/Oct/2015:11:48:21 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 45.72.9.89 - - [28/Oct/2015:11:48:24 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 45.72.9.89 - - [28/Oct/2015:11:48:25 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 45.72.9.89 - - [28/Oct/2015:11:48:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 45.72.9.89 - - [28/Oct/2015:11:48:28 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 45.72.9.89 - - [28/Oct/2015:11:48:29 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 94.23.33.25 - - [28/Oct/2015:11:55:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.52.204.252 - - [28/Oct/2015:11:55:20 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.52.204.252 - - [28/Oct/2015:11:55:23 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.52.204.252 - - [28/Oct/2015:11:55:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.52.204.252 - - [28/Oct/2015:11:55:31 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.52.204.252 - - [28/Oct/2015:11:55:32 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:11:59:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.52.204.252 - - [28/Oct/2015:11:59:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.99.99.59 - - [28/Oct/2015:12:01:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.99.99.59 - - [28/Oct/2015:12:01:25 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.99.99.59 - - [28/Oct/2015:12:01:26 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 91.99.99.59 - - [28/Oct/2015:12:01:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:12:05:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.68 - - [28/Oct/2015:12:05:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.231.24.101 - - [28/Oct/2015:12:06:02 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 23.231.24.101 - - [28/Oct/2015:12:06:03 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 23.231.24.101 - - [28/Oct/2015:12:06:04 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 23.231.24.101 - - [28/Oct/2015:12:06:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 23.231.24.101 - - [28/Oct/2015:12:06:06 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 23.231.24.101 - - [28/Oct/2015:12:06:07 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 154.16.72.210 - - [28/Oct/2015:12:08:59 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:12:08:59 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:12:09:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:12:09:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:12:09:01 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:12:09:02 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:12:09:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.68 - - [28/Oct/2015:12:09:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:12:15:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 69.12.79.105 - - [28/Oct/2015:12:15:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:12:23:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.184 - - [28/Oct/2015:12:23:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.31 - - [28/Oct/2015:12:26:20 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.31 - - [28/Oct/2015:12:26:21 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.31 - - [28/Oct/2015:12:26:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.31 - - [28/Oct/2015:12:26:24 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.31 - - [28/Oct/2015:12:26:26 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:12:28:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.12.117.57 - - [28/Oct/2015:12:28:40 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.12.117.57 - - [28/Oct/2015:12:28:42 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.12.117.57 - - [28/Oct/2015:12:28:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.12.117.57 - - [28/Oct/2015:12:28:45 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.12.117.57 - - [28/Oct/2015:12:28:47 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 94.23.33.25 - - [28/Oct/2015:12:31:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.12.117.57 - - [28/Oct/2015:12:31:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:13:09:06 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.1" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:13:09:10 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:13:09:12 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:13:09:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.200.24.243 - - [28/Oct/2015:13:09:58 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.200.24.243 - - [28/Oct/2015:13:09:59 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.200.24.243 - - [28/Oct/2015:13:10:01 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.200.24.243 - - [28/Oct/2015:13:10:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.200.24.243 - - [28/Oct/2015:13:10:04 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.200.24.243 - - [28/Oct/2015:13:10:05 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.211.162.129 - - [28/Oct/2015:13:11:27 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.211.162.129 - - [28/Oct/2015:13:11:28 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.211.162.129 - - [28/Oct/2015:13:11:28 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.211.162.129 - - [28/Oct/2015:13:11:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.211.162.129 - - [28/Oct/2015:13:11:30 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.211.162.129 - - [28/Oct/2015:13:11:31 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.218.192.205 - - [28/Oct/2015:13:12:27 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19422 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.218.192.205 - - [28/Oct/2015:13:12:28 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.218.192.205 - - [28/Oct/2015:13:12:29 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.218.192.205 - - [28/Oct/2015:13:12:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.218.192.205 - - [28/Oct/2015:13:12:31 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.218.192.205 - - [28/Oct/2015:13:12:32 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.234.188 - - [28/Oct/2015:13:31:14 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.234.188 - - [28/Oct/2015:13:31:16 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.234.188 - - [28/Oct/2015:13:31:17 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.234.188 - - [28/Oct/2015:13:31:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.234.188 - - [28/Oct/2015:13:31:20 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.23.234.188 - - [28/Oct/2015:13:31:21 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.102.99.141 - - [28/Oct/2015:13:39:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [28/Oct/2015:13:39:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 195.154.240.173 - - [28/Oct/2015:13:44:29 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 195.154.240.173 - - [28/Oct/2015:13:44:30 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 195.154.240.173 - - [28/Oct/2015:13:44:30 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 195.154.240.173 - - [28/Oct/2015:13:44:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 195.154.240.173 - - [28/Oct/2015:13:44:31 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 195.154.240.173 - - [28/Oct/2015:13:44:31 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 180.180.108.65 - - [28/Oct/2015:13:49:25 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.108.65 - - [28/Oct/2015:13:49:27 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.108.65 - - [28/Oct/2015:13:49:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.108.65 - - [28/Oct/2015:13:49:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.108.65 - - [28/Oct/2015:13:49:34 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 180.180.108.65 - - [28/Oct/2015:13:49:36 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.42.226 - - [28/Oct/2015:14:03:36 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.42.226 - - [28/Oct/2015:14:03:37 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.42.226 - - [28/Oct/2015:14:03:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.42.226 - - [28/Oct/2015:14:03:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.42.226 - - [28/Oct/2015:14:03:41 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.42.226 - - [28/Oct/2015:14:03:42 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 66.150.34.163 - - [28/Oct/2015:14:04:59 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 66.150.34.163 - - [28/Oct/2015:14:05:01 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 66.150.34.163 - - [28/Oct/2015:14:05:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 66.150.34.163 - - [28/Oct/2015:14:05:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 66.150.34.163 - - [28/Oct/2015:14:05:04 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 66.150.34.163 - - [28/Oct/2015:14:05:05 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 88.150.210.88 - - [28/Oct/2015:14:15:08 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 88.150.210.88 - - [28/Oct/2015:14:15:09 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.59 - - [28/Oct/2015:14:19:51 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.59 - - [28/Oct/2015:14:19:53 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.59 - - [28/Oct/2015:14:19:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.59 - - [28/Oct/2015:14:19:56 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.161.84.59 - - [28/Oct/2015:14:19:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:14:33:40 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.1" 200 25009 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:14:33:45 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:14:33:49 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:14:33:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:15:14:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:15:14:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:15:14:29 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:15:31:26 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:15:31:28 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:15:31:28 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:15:31:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:15:31:30 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [28/Oct/2015:15:31:31 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.194.105 - - [28/Oct/2015:15:43:50 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.194.105 - - [28/Oct/2015:15:43:52 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.194.105 - - [28/Oct/2015:15:43:53 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.194.105 - - [28/Oct/2015:15:43:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.194.105 - - [28/Oct/2015:15:43:56 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.194.105 - - [28/Oct/2015:15:43:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:15:48:59 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.1" 200 19422 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:15:49:02 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:15:49:04 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:15:49:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:15:52:12 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:15:52:13 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:15:52:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:15:52:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:15:52:16 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:15:52:17 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:16:00:08 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64/My-first-howto HTTP/1.1" 200 20024 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:16:00:11 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:16:00:13 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:16:00:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:16:02:38 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:16:02:39 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:16:02:40 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:16:02:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:16:02:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.113.224 - - [28/Oct/2015:16:02:43 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:16:37:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:16:37:40 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:16:37:42 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 212.83.141.47 - - [28/Oct/2015:16:40:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.144.182.150 - - [28/Oct/2015:16:40:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [28/Oct/2015:16:41:00 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [28/Oct/2015:16:41:01 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [28/Oct/2015:16:41:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [28/Oct/2015:16:41:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [28/Oct/2015:16:41:05 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [28/Oct/2015:16:41:06 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 113.140.43.51 - - [28/Oct/2015:16:47:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 113.140.43.51 - - [28/Oct/2015:16:47:25 +0100] "GET /login_form HTTP/1.0" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.254.212.109 - - [28/Oct/2015:16:54:09 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.254.212.109 - - [28/Oct/2015:16:54:11 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.254.212.109 - - [28/Oct/2015:16:54:12 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.254.212.109 - - [28/Oct/2015:16:54:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.254.212.109 - - [28/Oct/2015:16:54:14 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.254.212.109 - - [28/Oct/2015:16:54:16 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.17.57.54 - - [28/Oct/2015:16:55:30 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.17.57.54 - - [28/Oct/2015:16:55:31 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.17.57.54 - - [28/Oct/2015:16:55:32 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.17.57.54 - - [28/Oct/2015:16:55:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.17.57.54 - - [28/Oct/2015:16:55:33 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 46.17.57.54 - - [28/Oct/2015:16:55:35 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:17:09:14 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:09:17 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:09:19 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:09:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.5.244 - - [28/Oct/2015:17:09:56 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.5.244 - - [28/Oct/2015:17:09:58 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.5.244 - - [28/Oct/2015:17:09:59 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.5.244 - - [28/Oct/2015:17:10:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.208.36.85 - - [28/Oct/2015:17:15:23 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.208.36.85 - - [28/Oct/2015:17:15:29 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.208.36.85 - - [28/Oct/2015:17:15:33 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.208.36.85 - - [28/Oct/2015:17:15:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.208.36.85 - - [28/Oct/2015:17:15:37 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.208.36.85 - - [28/Oct/2015:17:15:39 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.200.122 - - [28/Oct/2015:17:18:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.200.122 - - [28/Oct/2015:17:18:11 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.200.122 - - [28/Oct/2015:17:18:12 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [28/Oct/2015:17:31:28 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [28/Oct/2015:17:31:31 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [28/Oct/2015:17:31:32 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [28/Oct/2015:17:31:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [28/Oct/2015:17:31:33 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [28/Oct/2015:17:31:34 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 190.235.197.227 - - [28/Oct/2015:17:43:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 190.235.197.227 - - [28/Oct/2015:17:43:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:50:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:50:09 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:50:10 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:59:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:59:53 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:17:59:55 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.127.116 - - [28/Oct/2015:18:03:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 167.160.127.116 - - [28/Oct/2015:18:03:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.132.58 - - [28/Oct/2015:18:52:45 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.144.132.58 - - [28/Oct/2015:18:52:46 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.144.132.58 - - [28/Oct/2015:18:52:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.144.132.58 - - [28/Oct/2015:18:52:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.144.132.58 - - [28/Oct/2015:18:52:49 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.144.132.58 - - [28/Oct/2015:18:52:49 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 66.248.205.240 - - [28/Oct/2015:18:56:17 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 66.248.205.240 - - [28/Oct/2015:18:56:18 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 66.248.205.240 - - [28/Oct/2015:18:56:19 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 66.248.205.240 - - [28/Oct/2015:18:56:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.199.158 - - [28/Oct/2015:19:06:15 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.199.158 - - [28/Oct/2015:19:06:17 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.199.158 - - [28/Oct/2015:19:06:19 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.199.158 - - [28/Oct/2015:19:06:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 173.44.194.237 - - [28/Oct/2015:19:10:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:19:10:02 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.44.194.237 - - [28/Oct/2015:19:10:06 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.201.102 - - [28/Oct/2015:19:16:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.201.102 - - [28/Oct/2015:19:16:25 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 216.158.201.102 - - [28/Oct/2015:19:16:27 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [28/Oct/2015:19:21:53 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [28/Oct/2015:19:21:56 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [28/Oct/2015:19:21:58 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [28/Oct/2015:19:22:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [28/Oct/2015:19:22:01 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [28/Oct/2015:19:22:03 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 148.251.65.34 - - [28/Oct/2015:19:23:49 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.57.165.41 - - [28/Oct/2015:19:23:50 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.57.165.41 - - [28/Oct/2015:19:23:51 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.57.165.41 - - [28/Oct/2015:19:23:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.57.165.41 - - [28/Oct/2015:19:23:54 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.57.165.41 - - [28/Oct/2015:19:23:55 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.169.2.207 - - [28/Oct/2015:19:46:15 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.169.2.207 - - [28/Oct/2015:19:46:22 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.169.2.207 - - [28/Oct/2015:19:46:24 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.227.173.86 - - [28/Oct/2015:19:48:02 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.227.173.86 - - [28/Oct/2015:19:48:03 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.227.173.86 - - [28/Oct/2015:19:48:05 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.227.173.86 - - [28/Oct/2015:19:48:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.227.173.86 - - [28/Oct/2015:19:48:07 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.227.173.86 - - [28/Oct/2015:19:48:08 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.19.69 - - [28/Oct/2015:19:49:48 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.19.69 - - [28/Oct/2015:19:49:51 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.19.69 - - [28/Oct/2015:19:49:52 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.19.69 - - [28/Oct/2015:19:49:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.19.69 - - [28/Oct/2015:19:49:55 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.19.69 - - [28/Oct/2015:19:49:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.46.229.187 - - [28/Oct/2015:19:50:14 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 198.46.229.187 - - [28/Oct/2015:19:50:15 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 198.46.229.187 - - [28/Oct/2015:19:50:16 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 198.46.229.187 - - [28/Oct/2015:19:50:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 198.46.229.187 - - [28/Oct/2015:19:50:18 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 198.46.229.187 - - [28/Oct/2015:19:50:19 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0 AlexaToolbar/alxf-2.21" 23.250.67.33 - - [28/Oct/2015:20:03:26 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.250.67.33 - - [28/Oct/2015:20:03:28 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.250.67.33 - - [28/Oct/2015:20:03:29 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.250.67.33 - - [28/Oct/2015:20:03:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.250.67.33 - - [28/Oct/2015:20:03:32 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.250.67.33 - - [28/Oct/2015:20:03:33 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 172.245.229.166 - - [28/Oct/2015:20:07:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 172.245.229.166 - - [28/Oct/2015:20:07:51 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 172.245.229.166 - - [28/Oct/2015:20:07:52 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 172.245.229.166 - - [28/Oct/2015:20:07:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.195.114 - - [28/Oct/2015:20:08:03 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.195.114 - - [28/Oct/2015:20:08:04 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.195.114 - - [28/Oct/2015:20:08:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.195.114 - - [28/Oct/2015:20:08:07 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.195.114 - - [28/Oct/2015:20:08:08 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:20:19:59 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.3.251.47 - - [28/Oct/2015:20:20:01 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.3.251.47 - - [28/Oct/2015:20:20:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.3.251.47 - - [28/Oct/2015:20:20:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:20:52:00 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.236.191.213 - - [28/Oct/2015:20:52:01 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.236.191.213 - - [28/Oct/2015:20:52:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.236.191.213 - - [28/Oct/2015:20:52:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.99.244.139 - - [28/Oct/2015:20:54:03 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 185.68.111.223 - - [28/Oct/2015:21:08:29 +0100] "GET /work HTTP/1.1" 200 17885 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.72.7.195 - - [28/Oct/2015:21:08:31 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.72.7.195 - - [28/Oct/2015:21:08:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 45.72.7.195 - - [28/Oct/2015:21:08:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.161.195.201 - - [28/Oct/2015:21:10:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.161.195.201 - - [28/Oct/2015:21:10:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 148.251.65.34 - - [28/Oct/2015:21:20:18 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.84 - - [28/Oct/2015:21:20:30 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 50.2.28.99 - - [28/Oct/2015:21:20:32 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 50.2.28.99 - - [28/Oct/2015:21:20:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 50.2.28.99 - - [28/Oct/2015:21:20:34 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 50.2.28.99 - - [28/Oct/2015:21:20:36 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:21:26:29 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.236.191.213 - - [28/Oct/2015:21:26:30 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.236.191.213 - - [28/Oct/2015:21:26:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.236.191.213 - - [28/Oct/2015:21:26:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.12.116 - - [28/Oct/2015:21:31:16 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 158.222.12.116 - - [28/Oct/2015:21:31:21 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 158.222.12.116 - - [28/Oct/2015:21:31:24 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 158.222.12.116 - - [28/Oct/2015:21:31:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 158.222.12.116 - - [28/Oct/2015:21:31:31 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 158.222.12.116 - - [28/Oct/2015:21:31:33 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 190.75.196.158 - - [28/Oct/2015:21:44:32 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 190.75.196.158 - - [28/Oct/2015:21:44:42 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 190.75.196.158 - - [28/Oct/2015:21:44:57 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.173.192.152 - - [28/Oct/2015:21:59:09 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.173.192.152 - - [28/Oct/2015:21:59:11 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.173.192.152 - - [28/Oct/2015:21:59:13 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.173.192.152 - - [28/Oct/2015:21:59:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.173.192.152 - - [28/Oct/2015:21:59:16 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 107.173.192.152 - - [28/Oct/2015:21:59:17 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 185.68.111.223 - - [28/Oct/2015:22:08:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.68.30 - - [28/Oct/2015:22:31:47 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.68.30 - - [28/Oct/2015:22:31:49 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.68.30 - - [28/Oct/2015:22:31:50 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.68.30 - - [28/Oct/2015:22:31:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.68.30 - - [28/Oct/2015:22:31:53 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.68.30 - - [28/Oct/2015:22:31:54 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:22:33:51 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.100.64 - - [28/Oct/2015:22:33:52 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.95.100.64 - - [28/Oct/2015:22:33:54 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:22:38:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.28.48 - - [28/Oct/2015:22:39:44 +0100] "GET / HTTP/1.0" 200 17057 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.28.48 - - [28/Oct/2015:22:39:45 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.28.48 - - [28/Oct/2015:22:39:47 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.28.48 - - [28/Oct/2015:22:39:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.28.48 - - [28/Oct/2015:22:39:49 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.144.28.48 - - [28/Oct/2015:22:39:51 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.161.195.211 - - [28/Oct/2015:22:55:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.161.195.211 - - [28/Oct/2015:22:55:56 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.161.195.211 - - [28/Oct/2015:22:55:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 88.150.236.121 - - [28/Oct/2015:23:00:56 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 88.150.236.121 - - [28/Oct/2015:23:00:57 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 88.150.236.121 - - [28/Oct/2015:23:00:57 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 88.150.236.121 - - [28/Oct/2015:23:00:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 88.150.236.121 - - [28/Oct/2015:23:00:58 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 88.150.236.121 - - [28/Oct/2015:23:00:59 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:23:29:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.247.146.31 - - [28/Oct/2015:23:29:07 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.247.146.31 - - [28/Oct/2015:23:29:08 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:23:32:25 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.223.29.240 - - [28/Oct/2015:23:32:27 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.223.29.240 - - [28/Oct/2015:23:32:28 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:23:40:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [28/Oct/2015:23:47:13 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.247.146.31 - - [28/Oct/2015:23:47:14 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 66.248.206.196 - - [28/Oct/2015:23:47:15 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 66.248.206.196 - - [28/Oct/2015:23:47:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.140.71.44 - - [28/Oct/2015:23:51:07 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.140.71.44 - - [28/Oct/2015:23:51:09 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.140.71.44 - - [28/Oct/2015:23:51:10 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.140.71.44 - - [28/Oct/2015:23:51:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.140.71.44 - - [28/Oct/2015:23:51:12 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.140.71.44 - - [28/Oct/2015:23:51:13 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 104.168.75.193 - - [29/Oct/2015:00:03:54 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.168.75.193 - - [29/Oct/2015:00:03:55 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.168.75.193 - - [29/Oct/2015:00:03:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.168.75.193 - - [29/Oct/2015:00:03:58 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.168.75.193 - - [29/Oct/2015:00:03:59 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 167.160.127.116 - - [29/Oct/2015:00:21:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 167.160.127.116 - - [29/Oct/2015:00:21:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 148.251.65.34 - - [29/Oct/2015:00:28:37 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.233 - - [29/Oct/2015:00:28:38 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.247 - - [29/Oct/2015:00:28:40 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.247 - - [29/Oct/2015:00:28:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.247 - - [29/Oct/2015:00:28:43 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 222.141.109.17 - - [29/Oct/2015:00:34:26 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 222.141.109.17 - - [29/Oct/2015:00:34:31 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 222.141.109.17 - - [29/Oct/2015:00:34:38 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 222.141.109.17 - - [29/Oct/2015:00:34:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 222.141.109.17 - - [29/Oct/2015:00:34:53 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 222.141.109.17 - - [29/Oct/2015:00:35:22 +0100] "POST /login_form HTTP/1.0" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.46.159.10 - - [29/Oct/2015:00:40:48 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.46.159.10 - - [29/Oct/2015:00:40:50 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.46.159.10 - - [29/Oct/2015:00:40:51 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.46.159.10 - - [29/Oct/2015:00:40:52 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 198.46.159.10 - - [29/Oct/2015:00:40:54 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.140.99 - - [29/Oct/2015:00:48:55 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.140.99 - - [29/Oct/2015:00:48:58 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.140.99 - - [29/Oct/2015:00:48:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.140.99 - - [29/Oct/2015:00:49:00 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 155.94.140.99 - - [29/Oct/2015:00:49:01 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 124.206.167.250 - - [29/Oct/2015:01:12:37 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 124.206.167.250 - - [29/Oct/2015:01:12:47 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 124.206.167.250 - - [29/Oct/2015:01:12:53 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 124.206.167.250 - - [29/Oct/2015:01:13:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 124.206.167.250 - - [29/Oct/2015:01:13:33 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 117.177.243.42 - - [29/Oct/2015:01:14:56 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 117.177.243.42 - - [29/Oct/2015:01:14:59 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:01:19:50 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:01:19:52 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:01:19:53 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:01:19:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:01:19:55 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:01:19:56 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.3.106.196 - - [29/Oct/2015:01:24:33 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 192.3.106.196 - - [29/Oct/2015:01:24:34 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 192.3.106.196 - - [29/Oct/2015:01:24:35 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 192.3.106.196 - - [29/Oct/2015:01:24:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 192.3.106.196 - - [29/Oct/2015:01:24:37 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 192.3.106.196 - - [29/Oct/2015:01:24:38 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 23.94.119.234 - - [29/Oct/2015:01:31:27 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.119.234 - - [29/Oct/2015:01:31:28 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 221.214.208.226 - - [29/Oct/2015:02:05:42 +0100] "GET /places HTTP/1.1" 200 12878 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 221.214.208.226 - - [29/Oct/2015:02:07:45 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 221.214.208.226 - - [29/Oct/2015:02:07:48 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 117.169.6.110 - - [29/Oct/2015:02:09:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form&last_visit:date=2015%2F10%2F29+02%3A13%3A13.091+GMT%2B1&prev_visit:date=2015%2F10%2F29+02%3A13%3A13.093+GMT%2B1&came_from_prefs=&fullname=Bonnie+Haddon&username=BonnieHadd&email=gil%40b.most-wanted-stuff.com&form.button.Register=Register&form.submitted=1 HTTP/1.1" 200 19101 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.173.193.178 - - [29/Oct/2015:02:11:08 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.193.178 - - [29/Oct/2015:02:11:08 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.193.178 - - [29/Oct/2015:02:11:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.193.178 - - [29/Oct/2015:02:11:10 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.201 - - [29/Oct/2015:02:15:22 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:02:15:23 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:02:15:24 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:02:15:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:02:15:24 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.201 - - [29/Oct/2015:02:15:25 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.99.244.139 - - [29/Oct/2015:02:16:53 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:02:16:54 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:02:16:55 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:02:16:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:02:16:57 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:02:16:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:02:31:36 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:02:31:38 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:02:31:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:02:31:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:02:31:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:02:31:43 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [29/Oct/2015:02:36:33 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 89.42.237.71 - - [29/Oct/2015:02:36:35 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 89.42.237.71 - - [29/Oct/2015:02:36:36 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 89.42.237.71 - - [29/Oct/2015:02:36:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 89.42.237.71 - - [29/Oct/2015:02:36:39 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 89.42.237.71 - - [29/Oct/2015:02:36:40 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [29/Oct/2015:03:05:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.30.157 - - [29/Oct/2015:03:36:46 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [29/Oct/2015:03:36:47 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [29/Oct/2015:03:36:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [29/Oct/2015:03:36:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [29/Oct/2015:03:36:48 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.220.30.157 - - [29/Oct/2015:03:36:49 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.232.137.128 - - [29/Oct/2015:03:45:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.232.137.128 - - [29/Oct/2015:03:45:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.108 - - [29/Oct/2015:04:01:04 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.108 - - [29/Oct/2015:04:01:05 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.108 - - [29/Oct/2015:04:01:06 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.108 - - [29/Oct/2015:04:01:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.108 - - [29/Oct/2015:04:01:07 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.108 - - [29/Oct/2015:04:01:07 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 162.253.52.250 - - [29/Oct/2015:04:07:05 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 162.253.52.250 - - [29/Oct/2015:04:07:06 +0100] "GET /join_form HTTP/1.1" 200 11114 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 162.253.52.250 - - [29/Oct/2015:04:07:07 +0100] "POST /join_form HTTP/1.1" 302 9245 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 162.253.52.250 - - [29/Oct/2015:04:07:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 162.253.52.250 - - [29/Oct/2015:04:07:08 +0100] "GET /login_form HTTP/1.1" 200 10505 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 162.253.52.250 - - [29/Oct/2015:04:07:09 +0100] "POST /login_form HTTP/1.1" 200 16772 "-" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 172.245.82.98 - - [29/Oct/2015:04:29:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.82.98 - - [29/Oct/2015:04:29:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 148.251.65.34 - - [29/Oct/2015:04:31:27 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.95 - - [29/Oct/2015:04:31:28 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 167.160.110.44 - - [29/Oct/2015:04:31:30 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 167.160.110.44 - - [29/Oct/2015:04:31:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 167.160.110.44 - - [29/Oct/2015:04:31:32 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 167.160.110.44 - - [29/Oct/2015:04:31:33 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [29/Oct/2015:04:34:44 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.251.69 - - [29/Oct/2015:04:34:45 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.251.69 - - [29/Oct/2015:04:34:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.251.69 - - [29/Oct/2015:04:34:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.46.135 - - [29/Oct/2015:04:44:36 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.12.82.152 - - [29/Oct/2015:04:44:37 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.12.82.152 - - [29/Oct/2015:04:44:38 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.12.82.152 - - [29/Oct/2015:04:44:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.247.99.226 - - [29/Oct/2015:04:51:04 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [29/Oct/2015:04:51:07 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [29/Oct/2015:04:51:09 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [29/Oct/2015:04:51:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [29/Oct/2015:04:51:14 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 104.247.99.226 - - [29/Oct/2015:04:51:16 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.46.135 - - [29/Oct/2015:05:05:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.251.47 - - [29/Oct/2015:05:05:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.217.216 - - [29/Oct/2015:05:16:54 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 155.94.217.216 - - [29/Oct/2015:05:16:56 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 155.94.217.216 - - [29/Oct/2015:05:16:57 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 155.94.217.216 - - [29/Oct/2015:05:16:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 155.94.217.216 - - [29/Oct/2015:05:16:59 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 155.94.217.216 - - [29/Oct/2015:05:17:00 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 192.99.244.139 - - [29/Oct/2015:05:17:00 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:05:17:02 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:05:17:03 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:05:17:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:05:17:04 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:05:17:05 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.46.135 - - [29/Oct/2015:05:24:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.251.112 - - [29/Oct/2015:05:24:30 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.46.135 - - [29/Oct/2015:05:26:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.247.146.31 - - [29/Oct/2015:05:26:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.66.103 - - [29/Oct/2015:05:27:10 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.66.103 - - [29/Oct/2015:05:27:12 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.66.103 - - [29/Oct/2015:05:27:13 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.66.103 - - [29/Oct/2015:05:27:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.66.103 - - [29/Oct/2015:05:27:15 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 23.94.66.103 - - [29/Oct/2015:05:27:17 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.99.244.139 - - [29/Oct/2015:05:27:18 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 121.204.77.53 - - [29/Oct/2015:05:44:46 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.1" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 121.204.77.53 - - [29/Oct/2015:05:44:48 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 121.204.77.53 - - [29/Oct/2015:05:44:49 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 121.204.77.53 - - [29/Oct/2015:05:44:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 121.204.77.53 - - [29/Oct/2015:05:44:51 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 121.204.77.53 - - [29/Oct/2015:05:44:53 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.16.72.210 - - [29/Oct/2015:06:01:52 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [29/Oct/2015:06:01:53 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [29/Oct/2015:06:01:54 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [29/Oct/2015:06:01:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [29/Oct/2015:06:01:55 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 154.16.72.210 - - [29/Oct/2015:06:01:56 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 31.187.79.212 - - [29/Oct/2015:06:06:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 31.187.79.212 - - [29/Oct/2015:06:06:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 148.251.65.34 - - [29/Oct/2015:06:14:06 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.10.36 - - [29/Oct/2015:06:14:07 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 158.222.12.205 - - [29/Oct/2015:06:14:09 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 172.245.225.201 - - [29/Oct/2015:06:26:06 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 172.245.225.201 - - [29/Oct/2015:06:26:08 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 172.245.225.201 - - [29/Oct/2015:06:26:09 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 172.245.225.201 - - [29/Oct/2015:06:26:10 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 172.245.225.201 - - [29/Oct/2015:06:26:11 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 172.245.225.201 - - [29/Oct/2015:06:26:12 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 195.154.216.59 - - [29/Oct/2015:06:29:00 +0100] "GET / HTTP/1.1" 200 20526 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.216.59 - - [29/Oct/2015:06:29:01 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.216.59 - - [29/Oct/2015:06:29:01 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.216.59 - - [29/Oct/2015:06:29:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.216.59 - - [29/Oct/2015:06:29:02 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 195.154.216.59 - - [29/Oct/2015:06:29:03 +0100] "POST /login_form HTTP/1.1" 200 18402 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 192.99.244.139 - - [29/Oct/2015:06:31:55 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.46.135 - - [29/Oct/2015:06:44:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.223.29.240 - - [29/Oct/2015:06:44:36 +0100] "GET /login_form HTTP/1.0" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.247.146.31 - - [29/Oct/2015:06:44:37 +0100] "POST /login_form HTTP/1.0" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2001:41d0:8:f69::1 - - [29/Oct/2015:06:47:36 +0100] "GET / HTTP/1.1" 200 20526 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2001:41d0:8:f69::1 - - [29/Oct/2015:06:47:37 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2001:41d0:8:f69::1 - - [29/Oct/2015:06:47:38 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2001:41d0:8:f69::1 - - [29/Oct/2015:06:47:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2001:41d0:8:f69::1 - - [29/Oct/2015:06:47:39 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2001:41d0:8:f69::1 - - [29/Oct/2015:06:47:39 +0100] "POST /login_form HTTP/1.1" 200 18402 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.44.18.186 - - [29/Oct/2015:06:58:55 +0100] "GET /contact-info HTTP/1.0" 200 15801 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 89.44.18.186 - - [29/Oct/2015:06:58:56 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 89.44.18.186 - - [29/Oct/2015:06:58:58 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 89.44.18.186 - - [29/Oct/2015:06:58:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 148.251.65.34 - - [29/Oct/2015:07:00:36 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.132 - - [29/Oct/2015:07:00:38 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.132 - - [29/Oct/2015:07:00:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.132 - - [29/Oct/2015:07:00:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.132 - - [29/Oct/2015:07:00:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 107.158.89.132 - - [29/Oct/2015:07:00:43 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 188.240.136.29 - - [29/Oct/2015:07:01:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 188.240.136.29 - - [29/Oct/2015:07:01:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 89.44.18.52 - - [29/Oct/2015:07:03:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 89.44.18.52 - - [29/Oct/2015:07:03:45 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 89.44.18.52 - - [29/Oct/2015:07:03:46 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 89.44.18.52 - - [29/Oct/2015:07:03:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/20100101 Firefox/17.0" 119.215.70.98 - - [29/Oct/2015:07:13:54 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.215.70.98 - - [29/Oct/2015:07:13:56 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.215.70.98 - - [29/Oct/2015:07:13:58 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.215.70.98 - - [29/Oct/2015:07:14:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.215.70.98 - - [29/Oct/2015:07:14:03 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 119.215.70.98 - - [29/Oct/2015:07:14:05 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 OPR/26.0.1656.60" 162.252.172.138 - - [29/Oct/2015:07:20:02 +0100] "GET / HTTP/1.1" 200 15381 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:07:20:04 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:07:20:08 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:07:20:10 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 46.102.99.140 - - [29/Oct/2015:07:20:54 +0100] "GET /author/nielsbasjes HTTP/1.0" 200 15519 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [29/Oct/2015:07:20:56 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [29/Oct/2015:07:21:02 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [29/Oct/2015:07:21:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [29/Oct/2015:07:21:06 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.140 - - [29/Oct/2015:07:21:08 +0100] "POST /login_form HTTP/1.1" 200 18241 "http://niels.basj.es/login_form" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 93.179.90.155 - - [29/Oct/2015:07:22:45 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 93.179.90.155 - - [29/Oct/2015:07:22:46 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 211.25.233.226 - - [29/Oct/2015:07:22:52 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 211.25.233.226 - - [29/Oct/2015:07:23:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 117.253.237.6 - - [29/Oct/2015:07:28:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 117.253.237.6 - - [29/Oct/2015:07:28:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:07:48:12 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:07:48:13 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:07:48:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:07:48:15 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:07:48:16 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 112.14.108.18 - - [29/Oct/2015:08:03:57 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 148.251.65.34 - - [29/Oct/2015:08:06:31 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 66.248.207.252 - - [29/Oct/2015:08:06:33 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 66.248.207.252 - - [29/Oct/2015:08:06:35 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 148.251.65.34 - - [29/Oct/2015:08:11:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.192.252 - - [29/Oct/2015:08:11:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 94.23.33.25 - - [29/Oct/2015:08:27:04 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.110.170 - - [29/Oct/2015:08:27:06 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.110.170 - - [29/Oct/2015:08:27:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.110.170 - - [29/Oct/2015:08:27:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.110.170 - - [29/Oct/2015:08:27:09 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.110.170 - - [29/Oct/2015:08:27:10 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.46.135 - - [29/Oct/2015:08:35:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.254.164.173 - - [29/Oct/2015:08:54:28 +0100] "GET /linux/installing-my-new-server/voice-over-ip/RK=0/RS=tDIUMWhLOlRs5FUbKMPumYVN.f0- HTTP/1.1" 404 12146 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36" 23.254.164.173 - - [29/Oct/2015:08:54:30 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/voice-over-ip/RK=0/RS=tDIUMWhLOlRs5FUbKMPumYVN.f0-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36" 23.254.164.173 - - [29/Oct/2015:08:54:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36" 23.254.164.173 - - [29/Oct/2015:08:54:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36" 23.254.164.173 - - [29/Oct/2015:08:54:33 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36" 23.254.164.173 - - [29/Oct/2015:08:54:34 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.52 Safari/537.36" 146.185.203.16 - - [29/Oct/2015:09:22:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 146.185.203.16 - - [29/Oct/2015:09:22:21 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 146.185.203.16 - - [29/Oct/2015:09:22:22 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [29/Oct/2015:09:41:34 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [29/Oct/2015:09:41:36 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [29/Oct/2015:09:41:37 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [29/Oct/2015:09:41:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [29/Oct/2015:09:41:40 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [29/Oct/2015:09:41:40 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2400:8900::f03c:91ff:fe50:5089 - - [29/Oct/2015:09:59:21 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2400:8900::f03c:91ff:fe50:5089 - - [29/Oct/2015:09:59:28 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2400:8900::f03c:91ff:fe50:5089 - - [29/Oct/2015:09:59:29 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2400:8900::f03c:91ff:fe50:5089 - - [29/Oct/2015:09:59:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2400:8900::f03c:91ff:fe50:5089 - - [29/Oct/2015:09:59:33 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 2400:8900::f03c:91ff:fe50:5089 - - [29/Oct/2015:09:59:34 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 61.92.43.177 - - [29/Oct/2015:10:35:46 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 61.92.43.177 - - [29/Oct/2015:10:35:49 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 61.92.43.177 - - [29/Oct/2015:10:35:51 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 61.92.43.177 - - [29/Oct/2015:10:35:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 61.92.43.177 - - [29/Oct/2015:10:35:54 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 61.92.43.177 - - [29/Oct/2015:10:35:56 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.195.150 - - [29/Oct/2015:10:42:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.195.150 - - [29/Oct/2015:10:42:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:10:48:26 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:10:48:29 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:10:48:30 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:10:48:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:10:48:34 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:10:48:35 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.175.205.75 - - [29/Oct/2015:10:57:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//fbsafetyguide.bravesites.com HTTP/1.0" 200 11743 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.175.205.75 - - [29/Oct/2015:10:57:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//fbsafetyguide.bravesites.com" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.175.205.75 - - [29/Oct/2015:10:57:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.243.125 - - [29/Oct/2015:11:10:28 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.243.125 - - [29/Oct/2015:11:10:30 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.243.125 - - [29/Oct/2015:11:10:31 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.243.125 - - [29/Oct/2015:11:10:32 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.243.125 - - [29/Oct/2015:11:10:33 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.243.125 - - [29/Oct/2015:11:10:34 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.226.70.214 - - [29/Oct/2015:11:14:08 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.226.70.214 - - [29/Oct/2015:11:14:09 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.226.70.214 - - [29/Oct/2015:11:14:10 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.226.70.214 - - [29/Oct/2015:11:14:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.226.70.214 - - [29/Oct/2015:11:14:12 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.226.70.214 - - [29/Oct/2015:11:14:13 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:11:29:09 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:11:29:21 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:11:29:26 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:11:29:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:11:30:56 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:11:30:57 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:11:30:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:11:30:59 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:11:31:00 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.243.62 - - [29/Oct/2015:11:31:36 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.243.62 - - [29/Oct/2015:11:31:37 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.243.62 - - [29/Oct/2015:11:31:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.243.62 - - [29/Oct/2015:11:31:39 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.173.243.62 - - [29/Oct/2015:11:31:40 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:11:41:04 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:11:41:06 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:11:41:11 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:11:41:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:11:41:18 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.119.9 - - [29/Oct/2015:11:41:20 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.12.158 - - [29/Oct/2015:11:41:50 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.5.244 - - [29/Oct/2015:11:41:52 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.5.244 - - [29/Oct/2015:11:41:53 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.5.244 - - [29/Oct/2015:11:41:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.77.254.250 - - [29/Oct/2015:11:42:07 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.0" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.77.254.250 - - [29/Oct/2015:11:42:08 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.77.254.250 - - [29/Oct/2015:11:42:10 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.77.254.250 - - [29/Oct/2015:11:42:11 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.77.254.250 - - [29/Oct/2015:11:42:12 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.77.254.250 - - [29/Oct/2015:11:42:13 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 60.12.11.39 - - [29/Oct/2015:11:48:59 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 60.12.11.39 - - [29/Oct/2015:11:49:11 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 60.12.11.39 - - [29/Oct/2015:11:49:17 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 60.12.11.39 - - [29/Oct/2015:11:49:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 60.12.11.39 - - [29/Oct/2015:11:49:30 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 60.12.11.39 - - [29/Oct/2015:11:49:35 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.52.212.18 - - [29/Oct/2015:12:04:07 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.52.212.18 - - [29/Oct/2015:12:04:09 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.52.212.18 - - [29/Oct/2015:12:04:10 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.52.212.18 - - [29/Oct/2015:12:04:11 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.52.212.18 - - [29/Oct/2015:12:04:12 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:12:06:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:12:06:28 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:12:06:36 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.108 - - [29/Oct/2015:12:20:17 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.108 - - [29/Oct/2015:12:20:18 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.108 - - [29/Oct/2015:12:20:18 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.108 - - [29/Oct/2015:12:20:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.108 - - [29/Oct/2015:12:20:19 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.187.79.108 - - [29/Oct/2015:12:20:20 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.82.231 - - [29/Oct/2015:12:20:41 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.82.231 - - [29/Oct/2015:12:20:42 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.82.231 - - [29/Oct/2015:12:20:44 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.82.231 - - [29/Oct/2015:12:20:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.82.231 - - [29/Oct/2015:12:20:49 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.82.231 - - [29/Oct/2015:12:20:51 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.119.149.217 - - [29/Oct/2015:12:27:11 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 192.119.149.217 - - [29/Oct/2015:12:27:13 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 192.119.149.217 - - [29/Oct/2015:12:27:14 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 192.119.149.217 - - [29/Oct/2015:12:27:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 192.119.149.217 - - [29/Oct/2015:12:27:15 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 192.119.149.217 - - [29/Oct/2015:12:27:16 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.24 - - [29/Oct/2015:12:35:18 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.24 - - [29/Oct/2015:12:35:21 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.24 - - [29/Oct/2015:12:35:24 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.24 - - [29/Oct/2015:12:35:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.12.31 - - [29/Oct/2015:12:37:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.24 - - [29/Oct/2015:12:37:53 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.24 - - [29/Oct/2015:12:37:55 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.24 - - [29/Oct/2015:12:42:39 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.197.14 - - [29/Oct/2015:12:42:52 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.197.14 - - [29/Oct/2015:12:42:54 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.197.14 - - [29/Oct/2015:12:42:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.12.76 - - [29/Oct/2015:12:47:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.201.102 - - [29/Oct/2015:12:47:55 +0100] "GET /login_form HTTP/1.0" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.201.102 - - [29/Oct/2015:12:47:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.119 - - [29/Oct/2015:12:50:34 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.119 - - [29/Oct/2015:12:50:36 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.119 - - [29/Oct/2015:12:50:38 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.119 - - [29/Oct/2015:12:50:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.119 - - [29/Oct/2015:12:50:41 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.119 - - [29/Oct/2015:12:50:43 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:12:52:44 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:12:52:47 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:12:52:54 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:12:52:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.168.75.182 - - [29/Oct/2015:13:01:27 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.168.75.182 - - [29/Oct/2015:13:01:28 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.168.75.182 - - [29/Oct/2015:13:01:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.168.75.182 - - [29/Oct/2015:13:01:30 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.168.75.182 - - [29/Oct/2015:13:01:31 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:13:08:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:13:09:13 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.157 - - [29/Oct/2015:13:10:37 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.157 - - [29/Oct/2015:13:10:39 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.157 - - [29/Oct/2015:13:10:41 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.157 - - [29/Oct/2015:13:10:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.157 - - [29/Oct/2015:13:10:45 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.184.157 - - [29/Oct/2015:13:10:47 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:13:12:13 +0100] "GET /search? HTTP/1.1" 200 10693 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:13:12:34 +0100] "GET /login_form HTTP/1.1" 200 11627 "http://niels.basjes.nl/search?" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 154.122.40.141 - - [29/Oct/2015:13:12:35 +0100] "POST /login_form HTTP/1.1" 200 18361 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.166.16 - - [29/Oct/2015:13:30:42 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.166.16 - - [29/Oct/2015:13:30:48 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.166.16 - - [29/Oct/2015:13:30:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.166.16 - - [29/Oct/2015:13:30:55 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.166.16 - - [29/Oct/2015:13:31:00 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.166.16 - - [29/Oct/2015:13:31:04 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.167.72 - - [29/Oct/2015:13:57:10 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.167.72 - - [29/Oct/2015:13:57:11 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.167.72 - - [29/Oct/2015:13:57:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.167.72 - - [29/Oct/2015:13:57:14 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.161.167.72 - - [29/Oct/2015:13:57:15 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.108.180.7 - - [29/Oct/2015:14:07:15 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.108.180.7 - - [29/Oct/2015:14:07:16 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.108.180.7 - - [29/Oct/2015:14:07:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.108.180.7 - - [29/Oct/2015:14:07:17 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.108.180.7 - - [29/Oct/2015:14:07:18 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 165.231.90.152 - - [29/Oct/2015:14:07:50 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 165.231.90.152 - - [29/Oct/2015:14:07:51 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 165.231.90.152 - - [29/Oct/2015:14:07:52 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 165.231.90.152 - - [29/Oct/2015:14:07:54 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 165.231.90.152 - - [29/Oct/2015:14:07:55 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.139.172.39 - - [29/Oct/2015:14:10:44 +0100] "GET / HTTP/1.1" 200 15381 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.139.172.39 - - [29/Oct/2015:14:10:45 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.139.172.39 - - [29/Oct/2015:14:10:45 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.139.172.39 - - [29/Oct/2015:14:10:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 212.129.17.73 - - [29/Oct/2015:14:15:15 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.250.147.37 - - [29/Oct/2015:14:15:18 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 46.102.99.131 - - [29/Oct/2015:14:35:30 +0100] "GET /join_form HTTP/1.0" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [29/Oct/2015:14:35:34 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [29/Oct/2015:14:35:35 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [29/Oct/2015:14:35:35 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [29/Oct/2015:14:35:36 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.131 - - [29/Oct/2015:14:35:39 +0100] "POST /login_form HTTP/1.1" 200 18241 "http://niels.basj.es/login_form" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 204.44.85.215 - - [29/Oct/2015:14:48:05 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 204.44.85.215 - - [29/Oct/2015:14:48:07 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 204.44.85.215 - - [29/Oct/2015:14:48:08 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 204.44.85.215 - - [29/Oct/2015:14:48:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 204.44.85.215 - - [29/Oct/2015:14:48:10 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 204.44.85.215 - - [29/Oct/2015:14:48:12 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 158.222.5.79 - - [29/Oct/2015:15:16:56 +0100] "GET /splittable-gzip HTTP/1.0" 200 27764 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.5.79 - - [29/Oct/2015:15:16:57 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 158.222.5.79 - - [29/Oct/2015:15:16:59 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:15:22:29 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:15:22:30 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:15:22:31 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:15:22:32 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.250.29.33 - - [29/Oct/2015:15:22:33 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.211 - - [29/Oct/2015:15:24:18 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.211 - - [29/Oct/2015:15:24:21 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.211 - - [29/Oct/2015:15:24:22 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.211 - - [29/Oct/2015:15:24:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.211 - - [29/Oct/2015:15:24:24 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.211 - - [29/Oct/2015:15:24:26 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:15:46:26 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:15:46:27 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:15:46:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:15:46:29 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.226.147 - - [29/Oct/2015:15:46:30 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.12.82.164 - - [29/Oct/2015:15:47:36 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 198.12.82.164 - - [29/Oct/2015:15:47:39 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 198.12.82.164 - - [29/Oct/2015:15:47:40 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 198.12.82.164 - - [29/Oct/2015:15:47:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 198.12.82.164 - - [29/Oct/2015:15:47:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 198.12.82.164 - - [29/Oct/2015:15:47:43 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 198.46.232.230 - - [29/Oct/2015:15:58:25 +0100] "GET /search?Subject%3Alist=Linux%20Installation HTTP/1.0" 200 11549 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.46.232.230 - - [29/Oct/2015:15:58:27 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.46.232.230 - - [29/Oct/2015:15:58:28 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.46.232.230 - - [29/Oct/2015:15:58:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.46.232.230 - - [29/Oct/2015:15:58:32 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.46.232.230 - - [29/Oct/2015:15:58:33 +0100] "POST /login_form HTTP/1.1" 200 16862 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.196 - - [29/Oct/2015:16:15:54 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.196 - - [29/Oct/2015:16:15:55 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.196 - - [29/Oct/2015:16:15:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.196 - - [29/Oct/2015:16:15:58 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.196 - - [29/Oct/2015:16:16:00 +0100] "POST /login_form HTTP/1.1" 200 16862 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.198 - - [29/Oct/2015:16:16:36 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.198 - - [29/Oct/2015:16:16:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.182.103 - - [29/Oct/2015:16:17:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.3.182.103 - - [29/Oct/2015:16:17:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.23.214.145 - - [29/Oct/2015:16:22:16 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.23.214.145 - - [29/Oct/2015:16:22:17 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.23.214.145 - - [29/Oct/2015:16:22:18 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.23.214.145 - - [29/Oct/2015:16:22:19 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 198.23.214.145 - - [29/Oct/2015:16:22:21 +0100] "POST /login_form HTTP/1.1" 200 16862 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.117 - - [29/Oct/2015:16:24:37 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.117 - - [29/Oct/2015:16:24:39 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.117 - - [29/Oct/2015:16:24:41 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.117 - - [29/Oct/2015:16:24:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.117 - - [29/Oct/2015:16:24:45 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 1.0.186.117 - - [29/Oct/2015:16:24:47 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.124 - - [29/Oct/2015:16:32:36 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.124 - - [29/Oct/2015:16:32:39 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.124 - - [29/Oct/2015:16:32:43 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.170.4 - - [29/Oct/2015:16:32:43 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.170.4 - - [29/Oct/2015:16:32:44 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.124 - - [29/Oct/2015:16:32:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.170.4 - - [29/Oct/2015:16:32:46 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.170.4 - - [29/Oct/2015:16:32:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.124 - - [29/Oct/2015:16:32:49 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.170.4 - - [29/Oct/2015:16:32:49 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.170.4 - - [29/Oct/2015:16:32:50 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.33.159.124 - - [29/Oct/2015:16:32:52 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.231.25.32 - - [29/Oct/2015:16:53:04 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.231.25.32 - - [29/Oct/2015:16:53:07 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.231.25.32 - - [29/Oct/2015:16:53:08 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.231.25.32 - - [29/Oct/2015:16:53:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.231.25.32 - - [29/Oct/2015:16:53:11 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.231.25.32 - - [29/Oct/2015:16:53:12 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 216.158.196.202 - - [29/Oct/2015:17:08:15 +0100] "GET / HTTP/1.1" 200 20478 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.202 - - [29/Oct/2015:17:08:17 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.202 - - [29/Oct/2015:17:08:18 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.202 - - [29/Oct/2015:17:08:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.202 - - [29/Oct/2015:17:08:21 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 216.158.196.202 - - [29/Oct/2015:17:08:22 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.99 Safari/537.36" 23.94.125.45 - - [29/Oct/2015:17:10:43 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.125.45 - - [29/Oct/2015:17:10:44 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.125.45 - - [29/Oct/2015:17:10:45 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.125.45 - - [29/Oct/2015:17:10:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.125.45 - - [29/Oct/2015:17:10:47 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.125.45 - - [29/Oct/2015:17:10:48 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 148.251.65.34 - - [29/Oct/2015:17:14:58 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.227.92.11 - - [29/Oct/2015:17:14:59 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.227.92.11 - - [29/Oct/2015:17:15:00 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.227.92.11 - - [29/Oct/2015:17:15:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.227.92.11 - - [29/Oct/2015:17:15:03 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 104.227.92.11 - - [29/Oct/2015:17:15:04 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 149.202.26.94 - - [29/Oct/2015:17:17:42 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 149.202.26.94 - - [29/Oct/2015:17:17:43 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 149.202.26.94 - - [29/Oct/2015:17:17:45 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 149.202.26.94 - - [29/Oct/2015:17:17:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 149.202.26.94 - - [29/Oct/2015:17:17:49 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 149.202.26.94 - - [29/Oct/2015:17:17:50 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.127.104 - - [29/Oct/2015:17:24:27 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.127.104 - - [29/Oct/2015:17:24:28 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:17:25:31 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:17:25:32 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:17:25:33 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:17:25:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:17:25:34 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:17:25:35 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 221.176.14.78 - - [29/Oct/2015:17:49:51 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 221.176.14.78 - - [29/Oct/2015:17:49:55 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 221.176.14.78 - - [29/Oct/2015:17:49:59 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 221.176.14.78 - - [29/Oct/2015:17:50:01 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 221.176.14.78 - - [29/Oct/2015:17:50:03 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 221.176.14.78 - - [29/Oct/2015:17:50:06 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0" 88.150.236.21 - - [29/Oct/2015:18:13:46 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 88.150.236.21 - - [29/Oct/2015:18:13:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 88.150.236.21 - - [29/Oct/2015:18:13:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 88.150.236.21 - - [29/Oct/2015:18:13:47 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 88.150.236.21 - - [29/Oct/2015:18:13:48 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:18:17:17 +0100] "GET / HTTP/1.1" 200 15381 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:18:17:19 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:18:17:21 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:18:17:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.127.116 - - [29/Oct/2015:18:20:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 167.160.127.116 - - [29/Oct/2015:18:20:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 50.2.211.101 - - [29/Oct/2015:18:22:36 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 50.2.211.101 - - [29/Oct/2015:18:22:37 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 50.2.211.101 - - [29/Oct/2015:18:22:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 50.2.211.101 - - [29/Oct/2015:18:22:39 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 50.2.211.101 - - [29/Oct/2015:18:22:40 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.107.129 - - [29/Oct/2015:18:39:23 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:18:39:26 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:18:39:27 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:18:39:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:18:39:31 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:18:39:36 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 155.94.138.198 - - [29/Oct/2015:19:09:47 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.138.198 - - [29/Oct/2015:19:09:49 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.138.198 - - [29/Oct/2015:19:09:53 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.138.198 - - [29/Oct/2015:19:09:55 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.138.198 - - [29/Oct/2015:19:09:57 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 46.102.99.141 - - [29/Oct/2015:19:25:02 +0100] "GET /join_form HTTP/1.0" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [29/Oct/2015:19:25:03 +0100] "GET /join_form HTTP/1.1" 200 12121 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [29/Oct/2015:19:25:06 +0100] "POST /join_form HTTP/1.1" 302 10098 "http://niels.basj.es/join_form" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [29/Oct/2015:19:25:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/join_form" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 46.102.99.141 - - [29/Oct/2015:19:25:08 +0100] "GET /login_form HTTP/1.1" 200 11544 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 180.180.107.129 - - [29/Oct/2015:19:36:28 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:36:30 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:36:32 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:36:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:36:35 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:36:36 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.227 - - [29/Oct/2015:19:41:20 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.227 - - [29/Oct/2015:19:41:22 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.227 - - [29/Oct/2015:19:41:24 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.227 - - [29/Oct/2015:19:41:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.227 - - [29/Oct/2015:19:41:27 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.227 - - [29/Oct/2015:19:41:28 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 162.252.172.138 - - [29/Oct/2015:19:44:17 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:19:44:20 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:19:44:21 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:19:44:23 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:19:44:24 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:19:44:26 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.107.129 - - [29/Oct/2015:19:50:18 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:50:21 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:50:23 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:50:24 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:50:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.107.129 - - [29/Oct/2015:19:50:29 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 69.57.235.224 - - [29/Oct/2015:20:22:07 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.229.97 - - [29/Oct/2015:20:25:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.229.97 - - [29/Oct/2015:20:25:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.216.59 - - [29/Oct/2015:20:26:11 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.216.59 - - [29/Oct/2015:20:26:12 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.216.59 - - [29/Oct/2015:20:26:12 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.216.59 - - [29/Oct/2015:20:26:13 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.216.59 - - [29/Oct/2015:20:26:13 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 195.154.216.59 - - [29/Oct/2015:20:26:14 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.82.89 - - [29/Oct/2015:20:32:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.82.89 - - [29/Oct/2015:20:32:42 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.82.89 - - [29/Oct/2015:20:32:44 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.82.89 - - [29/Oct/2015:20:32:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.82.89 - - [29/Oct/2015:20:32:48 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 172.245.82.89 - - [29/Oct/2015:20:32:50 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:20:50:43 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:20:50:45 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:20:50:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:20:50:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:20:50:50 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 162.252.172.138 - - [29/Oct/2015:20:50:52 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.108.180.195 - - [29/Oct/2015:21:21:42 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 91.108.180.191 - - [29/Oct/2015:21:21:43 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 75.127.10.67 - - [29/Oct/2015:21:39:04 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.0" 200 25009 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 75.127.10.67 - - [29/Oct/2015:21:39:07 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 75.127.10.67 - - [29/Oct/2015:21:39:08 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 75.127.10.67 - - [29/Oct/2015:21:39:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 75.127.10.67 - - [29/Oct/2015:21:39:10 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 75.127.10.67 - - [29/Oct/2015:21:39:11 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.232.116.147 - - [29/Oct/2015:21:42:04 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.232.116.147 - - [29/Oct/2015:21:42:06 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.232.116.147 - - [29/Oct/2015:21:42:07 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.232.116.147 - - [29/Oct/2015:21:42:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.232.116.147 - - [29/Oct/2015:21:42:09 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 173.232.116.147 - - [29/Oct/2015:21:42:10 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.168.77 - - [29/Oct/2015:22:11:32 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.168.77 - - [29/Oct/2015:22:11:37 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.168.77 - - [29/Oct/2015:22:11:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.168.77 - - [29/Oct/2015:22:11:48 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.168.77 - - [29/Oct/2015:22:11:53 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:30:22 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:30:23 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:30:24 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:30:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:30:26 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:30:27 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.16.36 - - [29/Oct/2015:22:48:01 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.16.36 - - [29/Oct/2015:22:48:02 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.16.36 - - [29/Oct/2015:22:48:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.16.36 - - [29/Oct/2015:22:48:05 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.94.16.36 - - [29/Oct/2015:22:48:07 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.236.191.148 - - [29/Oct/2015:22:52:35 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.236.191.148 - - [29/Oct/2015:22:52:37 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.236.191.148 - - [29/Oct/2015:22:52:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.236.191.148 - - [29/Oct/2015:22:52:40 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.236.191.148 - - [29/Oct/2015:22:52:41 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:58:14 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:58:15 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:58:16 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:58:16 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:58:17 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:22:58:18 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.30.157 - - [29/Oct/2015:23:05:36 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.30.157 - - [29/Oct/2015:23:05:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.30.157 - - [29/Oct/2015:23:05:38 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.30.157 - - [29/Oct/2015:23:05:39 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.30.157 - - [29/Oct/2015:23:05:40 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.30.157 - - [29/Oct/2015:23:05:40 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:23:15:23 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:23:15:24 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:23:15:25 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:23:15:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:23:15:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [29/Oct/2015:23:15:27 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.36.65.53 - - [29/Oct/2015:23:18:38 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.36.65.53 - - [29/Oct/2015:23:18:39 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.36.65.53 - - [29/Oct/2015:23:18:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.36.65.53 - - [29/Oct/2015:23:18:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.36.65.53 - - [29/Oct/2015:23:18:41 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.36.65.53 - - [29/Oct/2015:23:18:42 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 94.23.33.25 - - [29/Oct/2015:23:38:45 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.145 - - [29/Oct/2015:23:38:47 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.145 - - [29/Oct/2015:23:38:49 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.145 - - [29/Oct/2015:23:38:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.145 - - [29/Oct/2015:23:38:52 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.145 - - [29/Oct/2015:23:38:53 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.39.5.5 - - [30/Oct/2015:00:00:59 +0100] "GET / HTTP/1.1" 200 17057 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 101.231.46.34 - - [30/Oct/2015:00:01:43 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 101.231.46.34 - - [30/Oct/2015:00:01:49 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 101.231.46.34 - - [30/Oct/2015:00:01:57 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 101.231.46.34 - - [30/Oct/2015:00:02:03 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.109.92 - - [30/Oct/2015:00:09:09 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.109.92 - - [30/Oct/2015:00:09:11 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.109.92 - - [30/Oct/2015:00:09:13 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.109.92 - - [30/Oct/2015:00:09:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.109.92 - - [30/Oct/2015:00:09:16 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.109.92 - - [30/Oct/2015:00:09:17 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 107.158.89.87 - - [30/Oct/2015:00:11:01 +0100] "GET / HTTP/1.0" 200 15381 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.87 - - [30/Oct/2015:00:11:03 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.87 - - [30/Oct/2015:00:11:04 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.158.89.87 - - [30/Oct/2015:00:11:06 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 23.95.16.212 - - [30/Oct/2015:00:30:16 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.0" 200 25009 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.95.16.212 - - [30/Oct/2015:00:30:19 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.105.174 - - [30/Oct/2015:00:30:21 +0100] "POST /join_form HTTP/1.0" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.105.174 - - [30/Oct/2015:00:30:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.105.174 - - [30/Oct/2015:00:30:24 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.105.174 - - [30/Oct/2015:00:30:26 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.218.192.116 - - [30/Oct/2015:00:34:46 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19422 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.218.192.116 - - [30/Oct/2015:00:34:47 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.218.192.116 - - [30/Oct/2015:00:34:48 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.218.192.116 - - [30/Oct/2015:00:34:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.218.192.116 - - [30/Oct/2015:00:34:50 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.218.192.116 - - [30/Oct/2015:00:34:53 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 94.23.33.25 - - [30/Oct/2015:00:40:35 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.4 - - [30/Oct/2015:00:40:37 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.4 - - [30/Oct/2015:00:40:38 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.4 - - [30/Oct/2015:00:40:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.4 - - [30/Oct/2015:00:40:41 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.4 - - [30/Oct/2015:00:40:43 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.175.177.230 - - [30/Oct/2015:00:41:46 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19422 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.175.177.230 - - [30/Oct/2015:00:41:47 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.175.177.230 - - [30/Oct/2015:00:41:47 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.175.177.230 - - [30/Oct/2015:00:41:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.175.177.230 - - [30/Oct/2015:00:41:48 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.175.177.230 - - [30/Oct/2015:00:41:48 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:00:49:26 +0100] "GET / HTTP/1.1" 200 15381 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:00:49:29 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:00:49:31 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:00:49:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.175.176.245 - - [30/Oct/2015:00:53:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.0" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 5.175.176.245 - - [30/Oct/2015:00:53:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basj.es/join_form HTTP/1.1" 200 11713 "http://niels.basj.es/" "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36" 173.208.43.114 - - [30/Oct/2015:01:16:04 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.43.114 - - [30/Oct/2015:01:16:06 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.43.114 - - [30/Oct/2015:01:16:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.43.114 - - [30/Oct/2015:01:16:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.43.114 - - [30/Oct/2015:01:16:09 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.36.49 - - [30/Oct/2015:01:50:29 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.36.49 - - [30/Oct/2015:01:50:31 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.36.49 - - [30/Oct/2015:01:50:33 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.36.49 - - [30/Oct/2015:01:50:38 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.36.49 - - [30/Oct/2015:01:50:43 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 173.208.36.49 - - [30/Oct/2015:01:50:45 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:02:43:05 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:02:43:06 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:02:43:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:02:43:08 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:02:43:09 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.190.144 - - [30/Oct/2015:02:56:57 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.190.144 - - [30/Oct/2015:02:57:00 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.190.144 - - [30/Oct/2015:02:57:01 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.190.144 - - [30/Oct/2015:02:57:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.190.144 - - [30/Oct/2015:02:57:05 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.190.144 - - [30/Oct/2015:02:57:06 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:03:05:43 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:03:05:44 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:03:05:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:03:05:46 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.167.104 - - [30/Oct/2015:03:05:47 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.188 - - [30/Oct/2015:03:09:14 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.51 - - [30/Oct/2015:03:09:18 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.51 - - [30/Oct/2015:03:09:19 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 155.94.221.220 - - [30/Oct/2015:03:23:01 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.221.220 - - [30/Oct/2015:03:23:03 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.221.220 - - [30/Oct/2015:03:23:04 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.221.220 - - [30/Oct/2015:03:23:05 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.221.220 - - [30/Oct/2015:03:23:07 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 45.57.167.114 - - [30/Oct/2015:03:37:38 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 45.57.167.114 - - [30/Oct/2015:03:37:39 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 45.57.167.114 - - [30/Oct/2015:03:37:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 45.57.167.114 - - [30/Oct/2015:03:37:41 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 45.57.167.114 - - [30/Oct/2015:03:37:42 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 158.222.2.215 - - [30/Oct/2015:04:01:39 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.2.215 - - [30/Oct/2015:04:01:45 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.2.215 - - [30/Oct/2015:04:01:46 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 158.222.2.215 - - [30/Oct/2015:04:01:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 107.172.0.248 - - [30/Oct/2015:04:09:08 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 107.172.0.248 - - [30/Oct/2015:04:09:10 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 107.172.0.248 - - [30/Oct/2015:04:09:11 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 107.172.0.248 - - [30/Oct/2015:04:09:12 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 107.172.0.248 - - [30/Oct/2015:04:09:13 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 107.172.0.248 - - [30/Oct/2015:04:09:14 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 204.44.114.62 - - [30/Oct/2015:04:12:13 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 204.44.114.62 - - [30/Oct/2015:04:12:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 204.44.114.62 - - [30/Oct/2015:04:12:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 204.44.114.62 - - [30/Oct/2015:04:12:16 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 204.44.114.62 - - [30/Oct/2015:04:12:17 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:27:13 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:27:16 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:27:17 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:27:19 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:27:21 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:27:24 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:29:10 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:29:12 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:29:14 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:29:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:29:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 1.0.181.200 - - [30/Oct/2015:04:29:19 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.236.191.148 - - [30/Oct/2015:04:59:44 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.236.191.148 - - [30/Oct/2015:04:59:45 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.236.191.148 - - [30/Oct/2015:04:59:46 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.236.191.148 - - [30/Oct/2015:04:59:47 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.236.191.148 - - [30/Oct/2015:04:59:47 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:06:54 +0100] "GET / HTTP/1.1" 302 281 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:06:56 +0100] "GET / HTTP/1.1" 200 20478 "http://basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:06:59 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:07:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:07:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.59.143 - - [30/Oct/2015:05:26:54 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.59.143 - - [30/Oct/2015:05:26:57 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.59.143 - - [30/Oct/2015:05:26:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.59.143 - - [30/Oct/2015:05:26:59 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.59.143 - - [30/Oct/2015:05:27:01 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 66.248.219.252 - - [30/Oct/2015:05:34:39 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 66.248.219.252 - - [30/Oct/2015:05:34:40 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 66.248.219.252 - - [30/Oct/2015:05:34:43 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 66.248.219.252 - - [30/Oct/2015:05:34:44 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.113.224 - - [30/Oct/2015:05:51:20 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.113.224 - - [30/Oct/2015:05:51:22 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.113.224 - - [30/Oct/2015:05:51:23 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.126.192.215 - - [30/Oct/2015:05:51:23 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 31.220.113.224 - - [30/Oct/2015:05:51:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.126.192.215 - - [30/Oct/2015:05:51:25 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 31.220.113.224 - - [30/Oct/2015:05:51:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 31.220.113.224 - - [30/Oct/2015:05:51:28 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 208.115.125.58 - - [30/Oct/2015:05:56:51 +0100] "GET /linux/installing-my-new-server/vmware-server HTTP/1.1" 200 25009 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:56:55 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:57:03 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:05:57:07 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.42.237.71 - - [30/Oct/2015:05:59:53 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [30/Oct/2015:05:59:54 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [30/Oct/2015:05:59:55 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [30/Oct/2015:05:59:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [30/Oct/2015:05:59:57 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 89.42.237.71 - - [30/Oct/2015:05:59:57 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 180.180.69.194 - - [30/Oct/2015:06:01:31 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.69.194 - - [30/Oct/2015:06:01:33 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.69.194 - - [30/Oct/2015:06:01:35 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.69.194 - - [30/Oct/2015:06:01:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.69.194 - - [30/Oct/2015:06:01:38 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.69.194 - - [30/Oct/2015:06:01:41 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.228 - - [30/Oct/2015:06:33:54 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.228 - - [30/Oct/2015:06:33:56 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.228 - - [30/Oct/2015:06:33:58 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.228 - - [30/Oct/2015:06:33:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.228 - - [30/Oct/2015:06:34:01 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.228 - - [30/Oct/2015:06:34:02 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.98.36 - - [30/Oct/2015:06:41:35 +0100] "GET /open-source HTTP/1.1" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.98.36 - - [30/Oct/2015:06:41:37 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.98.36 - - [30/Oct/2015:06:41:39 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.98.36 - - [30/Oct/2015:06:41:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.98.36 - - [30/Oct/2015:06:41:42 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.98.36 - - [30/Oct/2015:06:41:43 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.157.42.183 - - [30/Oct/2015:06:46:37 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.157.42.183 - - [30/Oct/2015:06:46:38 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.157.42.183 - - [30/Oct/2015:06:46:39 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.157.42.183 - - [30/Oct/2015:06:46:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.157.42.183 - - [30/Oct/2015:06:46:40 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 5.157.42.183 - - [30/Oct/2015:06:46:41 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.255.101.129 - - [30/Oct/2015:06:56:23 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.255.101.129 - - [30/Oct/2015:06:56:24 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.255.101.129 - - [30/Oct/2015:06:56:25 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 69.163.47.119 - - [30/Oct/2015:06:58:17 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 117.169.1.109 - - [30/Oct/2015:06:58:54 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 117.169.1.109 - - [30/Oct/2015:06:58:57 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 117.169.1.109 - - [30/Oct/2015:06:58:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 117.169.1.109 - - [30/Oct/2015:06:59:01 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 117.169.1.109 - - [30/Oct/2015:06:59:04 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.215.54 - - [30/Oct/2015:07:08:44 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.215.54 - - [30/Oct/2015:07:08:45 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.215.54 - - [30/Oct/2015:07:08:47 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.215.54 - - [30/Oct/2015:07:08:48 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.215.54 - - [30/Oct/2015:07:08:49 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 155.94.215.54 - - [30/Oct/2015:07:08:50 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 208.115.125.58 - - [30/Oct/2015:07:08:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:07:09:09 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:07:09:12 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 172.245.229.166 - - [30/Oct/2015:07:18:33 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 172.245.229.166 - - [30/Oct/2015:07:18:34 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 172.245.229.166 - - [30/Oct/2015:07:18:35 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 172.245.229.166 - - [30/Oct/2015:07:18:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 82.211.57.224 - - [30/Oct/2015:07:40:40 +0100] "GET / HTTP/1.0" 302 285 "http://www.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 82.211.57.224 - - [30/Oct/2015:07:40:40 +0100] "GET / HTTP/1.0" 200 20478 "http://www.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 82.211.57.224 - - [30/Oct/2015:07:40:41 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 82.211.57.224 - - [30/Oct/2015:07:40:41 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 82.211.57.224 - - [30/Oct/2015:07:40:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 82.211.57.224 - - [30/Oct/2015:07:40:43 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 82.211.57.224 - - [30/Oct/2015:07:40:43 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Dragon/36.1.1.21 Chrome/36.0.1985.97 Safari/537.36" 192.99.244.139 - - [30/Oct/2015:07:40:56 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:07:40:58 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:07:40:58 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:07:40:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:07:41:00 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:07:41:01 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 27.156.72.98 - - [30/Oct/2015:07:50:46 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.1" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 27.156.72.98 - - [30/Oct/2015:07:50:48 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 27.156.72.98 - - [30/Oct/2015:07:50:49 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 27.156.72.98 - - [30/Oct/2015:07:50:50 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 27.156.72.98 - - [30/Oct/2015:07:50:51 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 27.156.72.98 - - [30/Oct/2015:07:50:52 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:08:01:14 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:08:01:17 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 208.115.125.58 - - [30/Oct/2015:08:01:20 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.168.92.23 - - [30/Oct/2015:08:21:09 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19422 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.168.92.23 - - [30/Oct/2015:08:21:22 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.168.92.23 - - [30/Oct/2015:08:21:24 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.168.92.23 - - [30/Oct/2015:08:21:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.168.92.23 - - [30/Oct/2015:08:21:31 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.168.92.23 - - [30/Oct/2015:08:21:32 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.95.195.29 - - [30/Oct/2015:08:28:27 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.95.195.29 - - [30/Oct/2015:08:28:28 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.95.195.29 - - [30/Oct/2015:08:28:29 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.95.195.29 - - [30/Oct/2015:08:28:30 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.95.195.29 - - [30/Oct/2015:08:28:32 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 110.80.69.214 - - [30/Oct/2015:09:00:07 +0100] "GET http://howto.basjes.nl/linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 110.80.69.214 - - [30/Oct/2015:09:00:14 +0100] "GET http://howto.basjes.nl/join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 110.80.69.214 - - [30/Oct/2015:09:00:29 +0100] "POST http://howto.basjes.nl/join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 110.80.69.214 - - [30/Oct/2015:09:00:32 +0100] "GET http://howto.basjes.nl/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 110.80.69.214 - - [30/Oct/2015:09:00:36 +0100] "GET http://howto.basjes.nl/login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 110.80.69.214 - - [30/Oct/2015:09:00:43 +0100] "POST http://howto.basjes.nl/login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 158.222.4.184 - - [30/Oct/2015:09:01:43 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 45.62.47.10 - - [30/Oct/2015:09:01:44 +0100] "POST /join_form HTTP/1.0" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.44.18.45 - - [30/Oct/2015:09:07:45 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0" 89.44.18.45 - - [30/Oct/2015:09:07:47 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0" 89.44.18.45 - - [30/Oct/2015:09:07:48 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0" 67.17.34.8 - - [30/Oct/2015:09:09:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//facebookscandals.jimdo.com HTTP/1.0" 200 11739 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 67.17.34.8 - - [30/Oct/2015:09:09:58 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/acl_users/credentials_cookie_auth/require_login?came_from=http%3A//facebookscandals.jimdo.com" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 67.17.34.8 - - [30/Oct/2015:09:10:00 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 67.17.34.8 - - [30/Oct/2015:09:10:01 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 67.17.34.8 - - [30/Oct/2015:09:10:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 188.240.133.156 - - [30/Oct/2015:09:12:34 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0" 188.240.133.156 - - [30/Oct/2015:09:12:35 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0" 188.240.133.156 - - [30/Oct/2015:09:12:36 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:34.0) Gecko/20100101 Firefox/34.0" 180.180.115.117 - - [30/Oct/2015:09:24:54 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.117 - - [30/Oct/2015:09:24:56 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.117 - - [30/Oct/2015:09:24:58 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.117 - - [30/Oct/2015:09:24:59 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.117 - - [30/Oct/2015:09:25:01 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.117 - - [30/Oct/2015:09:25:15 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.140.71.83 - - [30/Oct/2015:09:35:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.140.71.83 - - [30/Oct/2015:09:35:42 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.140.71.83 - - [30/Oct/2015:09:35:43 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.126.192.175 - - [30/Oct/2015:09:39:48 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.126.192.175 - - [30/Oct/2015:09:39:50 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.126.192.175 - - [30/Oct/2015:09:39:52 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.126.192.175 - - [30/Oct/2015:09:39:54 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.3.242.26 - - [30/Oct/2015:09:51:33 +0100] "GET / HTTP/1.0" 200 15381 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.3.242.26 - - [30/Oct/2015:09:51:35 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.3.242.26 - - [30/Oct/2015:09:51:36 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.3.242.26 - - [30/Oct/2015:09:51:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.10.8 - - [30/Oct/2015:10:05:20 +0100] "GET /linux/installing-my-new-server/networking HTTP/1.0" 200 27452 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.10.8 - - [30/Oct/2015:10:05:35 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.10.8 - - [30/Oct/2015:10:05:52 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.10.8 - - [30/Oct/2015:10:06:09 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.10.8 - - [30/Oct/2015:10:06:12 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.94.10.8 - - [30/Oct/2015:10:06:27 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 212.129.17.73 - - [30/Oct/2015:10:10:17 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 201.22.59.126 - - [30/Oct/2015:10:10:34 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 60.191.163.235 - - [30/Oct/2015:10:11:18 +0100] "POST /join_form HTTP/1.0" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 60.191.163.235 - - [30/Oct/2015:10:11:21 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.0" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.33.71.249 - - [30/Oct/2015:10:30:03 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.33.71.249 - - [30/Oct/2015:10:30:04 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.33.71.249 - - [30/Oct/2015:10:30:05 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.33.71.249 - - [30/Oct/2015:10:30:05 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.33.71.249 - - [30/Oct/2015:10:30:06 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.232.137.128 - - [30/Oct/2015:10:33:53 +0100] "GET /linux/installing-gitlab-on-centos-6 HTTP/1.0" 200 19422 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.232.137.128 - - [30/Oct/2015:10:33:54 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.232.137.128 - - [30/Oct/2015:10:33:55 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.232.137.128 - - [30/Oct/2015:10:33:56 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.232.137.128 - - [30/Oct/2015:10:33:58 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.232.137.128 - - [30/Oct/2015:10:33:59 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:10:35:20 +0100] "GET /accessibility-info HTTP/1.1" 200 20626 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:10:35:21 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:10:35:22 +0100] "POST /join_form HTTP/1.1" 302 10322 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:10:35:22 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:10:35:23 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.99.244.139 - - [30/Oct/2015:10:35:24 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 148.251.65.34 - - [30/Oct/2015:10:45:57 +0100] "GET /linux/installing-fedora-linux-via-pxe-x86-64 HTTP/1.1" 200 36444 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 66.248.210.252 - - [30/Oct/2015:10:46:00 +0100] "GET /join_form HTTP/1.0" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 66.248.210.252 - - [30/Oct/2015:10:46:01 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 66.248.210.252 - - [30/Oct/2015:10:46:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 66.248.210.252 - - [30/Oct/2015:10:46:03 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 66.248.210.252 - - [30/Oct/2015:10:46:04 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.118.146 - - [30/Oct/2015:10:56:19 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.118.146 - - [30/Oct/2015:10:56:21 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.118.146 - - [30/Oct/2015:10:56:24 +0100] "POST /join_form HTTP/1.1" 302 9245 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.118.146 - - [30/Oct/2015:10:56:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.118.146 - - [30/Oct/2015:10:56:27 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.118.146 - - [30/Oct/2015:10:56:29 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.102.254.132 - - [30/Oct/2015:11:00:47 +0100] "GET /places HTTP/1.1" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.102.254.132 - - [30/Oct/2015:11:00:48 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.102.254.132 - - [30/Oct/2015:11:00:49 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.102.254.132 - - [30/Oct/2015:11:00:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.102.254.132 - - [30/Oct/2015:11:00:50 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 5.102.254.132 - - [30/Oct/2015:11:00:51 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 212.83.141.47 - - [30/Oct/2015:11:11:41 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.200.60 - - [30/Oct/2015:11:41:42 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.200.60 - - [30/Oct/2015:11:41:44 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.200.60 - - [30/Oct/2015:11:41:45 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.201.102 - - [30/Oct/2015:11:48:22 +0100] "GET /open-source HTTP/1.0" 200 17529 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.201.102 - - [30/Oct/2015:11:48:30 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.201.102 - - [30/Oct/2015:11:48:32 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.201.102 - - [30/Oct/2015:11:48:33 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.222.163 - - [30/Oct/2015:11:49:04 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.0" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.222.163 - - [30/Oct/2015:11:49:05 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.222.163 - - [30/Oct/2015:11:49:07 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.222.163 - - [30/Oct/2015:11:49:08 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 158.222.8.217 - - [30/Oct/2015:11:53:02 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.0" 200 11793 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 158.222.12.76 - - [30/Oct/2015:11:53:07 +0100] "GET /login_form HTTP/1.0" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.197.69 - - [30/Oct/2015:11:54:15 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.197.69 - - [30/Oct/2015:11:54:16 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 216.158.197.69 - - [30/Oct/2015:11:54:18 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.188 - - [30/Oct/2015:11:59:40 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.0" 200 10716 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.188 - - [30/Oct/2015:11:59:45 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.188 - - [30/Oct/2015:11:59:46 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.188 - - [30/Oct/2015:11:59:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.188 - - [30/Oct/2015:11:59:49 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.128.23.188 - - [30/Oct/2015:11:59:51 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 212.129.17.73 - - [30/Oct/2015:12:29:20 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 212.129.17.73 - - [30/Oct/2015:12:29:51 +0100] "GET / HTTP/1.1" 200 15381 "http://daniel_en_sander.basjes.nl" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 183.203.23.135 - - [30/Oct/2015:12:29:54 +0100] "GET /join_form HTTP/1.1" 200 11652 "http://daniel_en_sander.basjes.nl" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 183.203.23.135 - - [30/Oct/2015:12:29:57 +0100] "POST /join_form HTTP/1.1" 302 9556 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 183.203.23.135 - - [30/Oct/2015:12:30:00 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//daniel_en_sander.basjes.nl/join_form HTTP/1.1" 403 340 "http://daniel_en_sander.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 88.150.210.88 - - [30/Oct/2015:12:33:31 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 88.150.210.88 - - [30/Oct/2015:12:33:32 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.144.18.94 - - [30/Oct/2015:12:44:59 +0100] "GET / HTTP/1.0" 200 20478 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.144.18.94 - - [30/Oct/2015:12:45:00 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.144.18.94 - - [30/Oct/2015:12:45:02 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.144.18.94 - - [30/Oct/2015:12:45:03 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.144.18.94 - - [30/Oct/2015:12:45:05 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 104.144.18.94 - - [30/Oct/2015:12:45:08 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 199.195.159.11 - - [30/Oct/2015:12:49:24 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 199.195.159.11 - - [30/Oct/2015:12:49:25 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 199.195.159.11 - - [30/Oct/2015:12:49:25 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 199.195.159.11 - - [30/Oct/2015:12:49:26 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 199.195.159.11 - - [30/Oct/2015:12:49:27 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.137 - - [30/Oct/2015:12:56:38 +0100] "GET /linux/doing-pxe-without-dhcp-control HTTP/1.1" 200 24323 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.137 - - [30/Oct/2015:12:56:46 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.137 - - [30/Oct/2015:12:56:47 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.137 - - [30/Oct/2015:12:56:49 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.137 - - [30/Oct/2015:12:56:57 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 180.180.115.137 - - [30/Oct/2015:12:57:02 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 23.254.164.173 - - [30/Oct/2015:14:35:34 +0100] "GET /linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8- HTTP/1.1" 404 12146 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36" 23.254.164.173 - - [30/Oct/2015:14:35:35 +0100] "GET /join_form HTTP/1.1" 200 11114 "http://howto.basjes.nl/linux/installing-my-new-server/voice-over-ip/RK=0/RS=YTkYTnGaf5QQxT7cm9uJgKS2rl8-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36" 23.254.164.173 - - [30/Oct/2015:14:35:36 +0100] "POST /join_form HTTP/1.1" 302 9093 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36" 23.254.164.173 - - [30/Oct/2015:14:35:37 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//howto.basjes.nl/join_form HTTP/1.1" 200 10716 "http://howto.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36" 23.254.164.173 - - [30/Oct/2015:14:35:38 +0100] "GET /login_form HTTP/1.1" 200 10543 "http://howto.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36" 23.254.164.173 - - [30/Oct/2015:14:35:40 +0100] "POST /login_form HTTP/1.1" 200 16810 "http://howto.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.63 Safari/537.36" 89.32.251.246 - - [30/Oct/2015:14:41:24 +0100] "GET /join_form HTTP/1.0" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.32.251.246 - - [30/Oct/2015:14:41:25 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.32.251.246 - - [30/Oct/2015:14:41:26 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.32.251.246 - - [30/Oct/2015:14:41:27 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 89.32.251.246 - - [30/Oct/2015:14:41:28 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 117.240.187.35 - - [30/Oct/2015:14:57:32 +0100] "GET /places HTTP/1.0" 200 19359 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 117.240.187.35 - - [30/Oct/2015:14:57:39 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 117.240.187.35 - - [30/Oct/2015:14:57:43 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 117.240.187.35 - - [30/Oct/2015:14:57:47 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 117.240.187.35 - - [30/Oct/2015:14:57:51 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 117.240.187.35 - - [30/Oct/2015:14:57:54 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.57.88 - - [30/Oct/2015:15:59:34 +0100] "GET /join_form HTTP/1.1" 200 12191 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.57.88 - - [30/Oct/2015:15:59:35 +0100] "POST /join_form HTTP/1.1" 302 10170 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.57.88 - - [30/Oct/2015:15:59:36 +0100] "GET /acl_users/credentials_cookie_auth/require_login?came_from=http%3A//niels.basjes.nl/join_form HTTP/1.1" 200 11793 "http://niels.basjes.nl/join_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.57.88 - - [30/Oct/2015:15:59:38 +0100] "GET /login_form HTTP/1.1" 200 11620 "http://niels.basjes.nl/" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" 192.161.57.88 - - [30/Oct/2015:15:59:39 +0100] "POST /login_form HTTP/1.1" 200 18354 "http://niels.basjes.nl/login_form" "Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0" ================================================ FILE: examples/java-pojo/pom.xml ================================================ 4.0.0 httpdlog-examples nl.basjes.parse.httpdlog.examples 6.0.1-SNAPSHOT java-pojo Parser - Examples - Java POJO nl.basjes.parse.httpdlog httpdlog-parser ${project.version} org.slf4j slf4j-reload4j ${slf4j.version} org.apache.maven.plugins maven-deploy-plugin true ================================================ FILE: examples/java-pojo/src/main/java/nl/basjes/parse/Main.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; public final class Main { private Main(){} private static final Logger LOG = LoggerFactory.getLogger(Main.class); private void printAllPossibles(String logformat) throws NoSuchMethodException, MissingDissectorsException, InvalidDissectorException { // To figure out what values we CAN get from this line we instantiate the parser with a dummy class // that does not have ANY @Field annotations. Parser dummyParser= new HttpdLoglineParser<>(Object.class, logformat); List possiblePaths; possiblePaths = dummyParser.getPossiblePaths(); // If you want to call 'getCasts' then the actual parser needs to be constructed. // Simply calling getPossiblePaths does not build the actual parser. // Because we want this for all possibilities yet we are never actually going to use this instance of the parser // We simply give it a random method with the right signature and tell it we want all possible paths dummyParser.addParseTarget(String.class.getMethod("indexOf", String.class), possiblePaths); LOG.info("=================================="); LOG.info("Possible output:"); for (String path : possiblePaths) { LOG.info("{} {}", path, dummyParser.getCasts(path)); } LOG.info("=================================="); } private void run() throws InvalidDissectorException, MissingDissectorsException, NoSuchMethodException, DissectionFailure { // This format and logline originate from here: // https://stackoverflow.com/questions/20349184/java-parse-log-file String logformat = "%t %u [%D %h %{True-Client-IP}i %{UNIQUE_ID}e %r] %{Cookie}i %s \"%{User-Agent}i\" \"%{host}i\" %l %b %{Referer}i"; String logline = "[02/Dec/2013:14:10:30 -0000] - [52075 10.102.4.254 177.43.52.210 UpyU1gpmBAwAACfd5W0AAAAW GET /SS14-VTam-ny_019.j" + "pg.rendition.zoomable.jpg HTTP/1.1] hsfirstvisit=http%3A%2F%2Fwww.domain.com%2Fen-us||1372268254000; _opt_vi_3FNG8DZU=F870" + "DCFD-CBA4-4B6E-BB58-4605A78EE71A; __ptca=145721067.0aDxsZlIuM48.1372279055.1379945057.1379950362.9; __ptv_62vY4e=0aDxsZlIu" + "M48; __pti_62vY4e=0aDxsZlIuM48; __ptcz=145721067.1372279055.1.0.ptmcsr=(direct)|ptmcmd=(none)|ptmccn=(direct); __hstc=1457" + "21067.b86362bb7a1d257bfa2d1fb77e128a85.1372268254968.1379934256743.1379939561848.9; hubspotutk=b86362bb7a1d257bfa2d1fb77e1" + "28a85; USER_GROUP=julinho%3Afalse; has_js=1; WT_FPC=id=177.43.52.210-1491335248.30301337:lv=1385997780893:ss=1385997780893" + "; dtCookie=1F2E0E1037589799D8D503EB8CFA12A1|_default|1; RM=julinho%3A5248423ad3fe062f06c54915e6cde5cb45147977; wcid=UpyKsQ" + "pmBAwAABURyNoAAAAS%3A35d8227ba1e8a9a9cebaaf8d019a74777c32b4c8; Carte::KerberosLexicon_getWGSN=82ae3dcd1b956288c3c86bdbed6e" + "bcc0fd040e1e; UserData=Username%3AJULINHO%3AHomepage%3A1%3AReReg%3A0%3ATrialist%3A0%3ALanguage%3Aen%3ACcode%3Abr%3AForceRe" + "Reg%3A0; UserID=1356673%3A12345%3A1234567890%3A123%3Accode%3Abr; USER_DATA=1356673%3Ajulinho%3AJulio+Jose%3Ada+Silva%3Ajul" + "inho%40tecnoblu.com.br%3A0%3A1%3Aen%3Abr%3A%3AWGSN%3A1385990833.81925%3A82ae3dcd1b956288c3c86bdbed6ebcc0fd040e1e; MODE=FON" + "TIS; SECTION=%2Fcontent%2Fsection%2Fhome.html; edge_auth=ip%3D177.43.52.210~expires%3D1385994522~access%3D%2Fapps%2F%2A%21" + "%2Fbin%2F%2A%21%2Fcontent%2F%2A%21%2Fetc%2F%2A%21%2Fhome%2F%2A%21%2Flibs%2F%2A%21%2Freport%2F%2A%21%2Fsection%2F%2A%21%2Fw" + "gsn%2F%2A~md5%3D90e73ee10161c1afacab12c6ea30b4ef; __utma=94539802.1793276213.1372268248.1385572390.1385990581.16; __utmb=9" + "4539802.52.9.1385991739764; __utmc=94539802; __utmz=94539802.1372268248.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);" + " WT_FPC=id=177.43.52.210-1491335248.30301337:lv=1386000374581:ss=1386000374581; dtPC=-; NSC_wtfswfs_xfcgbsn40-41=ffffffff0" + "96e1a1d45525d5f4f58455e445a4a423660; akamai-edge=5ac6e5b3d0bbe2ea771bb2916d8bab34ea222a6a 200 \"Mozilla/5.0 (Windows NT 6." + "2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36\" \"www.domain.com\" - 463952 http://ww" + "w.domain.com/content/report/shows/New_York/KSHK/trip/s_s_14_ny_ww/sheers.html"; printAllPossibles(logformat); Parser parser = new HttpdLoglineParser<>(MyRecord.class, logformat); MyRecord record = new MyRecord(); LOG.info("=================================================================================="); parser.parse(record, logline); LOG.info(record.toString()); LOG.info("=================================================================================="); } public static void main(final String[] args) throws Exception { new Main().run(); } } ================================================ FILE: examples/java-pojo/src/main/java/nl/basjes/parse/MyRecord.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse; import nl.basjes.parse.core.Field; import java.util.HashMap; import java.util.Map; import java.util.TreeSet; public class MyRecord { private final Map results = new HashMap<>(32); @Field("STRING:request.firstline.uri.query.*") public void setQueryDeepMany(final String name, final String value) { results.put(name, value); } @Field("STRING:request.firstline.uri.query.img") public void setQueryImg(final String name, final String value) { results.put(name, value); } @Field("IP:connection.client.host") public void setIP(final String value) { results.put("IP:connection.client.host", value); } @Field({ "HTTP.QUERYSTRING:request.firstline.uri.query", "NUMBER:connection.client.logname", "STRING:connection.client.user", "TIME.STAMP:request.receive.time", "HTTP.URI:request.firstline.uri", "BYTESCLF:response.body.bytes", "HTTP.URI:request.referer", "HTTP.USERAGENT:request.user-agent", "TIME.DAY:request.receive.time.day", "TIME.HOUR:request.receive.time.hour", "TIME.MONTHNAME:request.receive.time.monthname" }) public void setValue(final String name, final String value) { results.put(name, value); } public String toString() { StringBuilder sb = new StringBuilder(); TreeSet keys = new TreeSet<>(results.keySet()); for (String key : keys) { sb.append(key).append(" = ").append(results.get(key)).append('\n'); } return sb.toString(); } public void clear() { results.clear(); } } ================================================ FILE: examples/java-pojo/src/main/resources/log4j.properties ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Root logger option log4j.rootLogger=INFO, stdout #, file log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.threshold=INFO log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n ## file appender #log4j.appender.file=org.apache.log4j.RollingFileAppender #log4j.appender.file.File=target/debug.log #log4j.appender.file.threshold=DEBUG #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n #log4j.appender.file.Append=false ================================================ FILE: examples/pom.xml ================================================ 4.0.0 parser-parent nl.basjes.parse 6.0.1-SNAPSHOT nl.basjes.parse.httpdlog.examples httpdlog-examples pom Parser - Examples - org.apache.maven.plugins maven-deploy-plugin true org.apache.maven.plugins maven-checkstyle-plugin org.jacoco jacoco-maven-plugin true org.apache.maven.plugins maven-enforcer-plugin dependency-convergence none java-pojo apache-hadoop-mapreduce apache-flink apache-beam ================================================ FILE: httpdlog/httpdlog-inputformat/pom.xml ================================================ 4.0.0 httpdlog nl.basjes.parse.httpdlog 6.0.1-SNAPSHOT httpdlog-inputformat Parser - Apache HTTPD - Hadoop InputFormat none org.apache.hadoop hadoop-client ${hadoop.version} provided ${project.groupId} httpdlog-parser ${project.version} nl.basjes.parse parser-core ${project.version} tests test org.jacoco jacoco-maven-plugin ================================================ FILE: httpdlog/httpdlog-inputformat/src/main/assembly/job.xml ================================================ job jar false false lib false compile org.slf4j:slf4j-api ${project.build.outputDirectory} ${file.separator} ================================================ FILE: httpdlog/httpdlog-inputformat/src/main/java/nl/basjes/hadoop/input/ApacheHttpdLogfileInputFormat.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.hadoop.input; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.compress.CompressionCodec; import org.apache.hadoop.io.compress.CompressionCodecFactory; import org.apache.hadoop.io.compress.SplittableCompressionCodec; import org.apache.hadoop.mapreduce.InputSplit; import org.apache.hadoop.mapreduce.JobContext; import org.apache.hadoop.mapreduce.RecordReader; import org.apache.hadoop.mapreduce.TaskAttemptContext; import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class ApacheHttpdLogfileInputFormat extends FileInputFormat { private String logFormat = null; private final Set requestedFields = new HashSet<>(); private Map> typeRemappings; private List additionalDissectors; private ApacheHttpdLogfileRecordReader theRecordReader; // -------------------------------------------- public List listPossibleFields(String logformat) { return listPossibleFields(logformat, typeRemappings, additionalDissectors); } public static List listPossibleFields(String logformat, Map> typeRemappings, List additionalDissectors) { HttpdLoglineParser parser = new HttpdLoglineParser<>(ParsedRecord.class, logformat); parser.setTypeRemappings(typeRemappings); parser.addDissectors(additionalDissectors); return parser.getPossiblePaths(); } public String getLogFormat() { return logFormat; } public Set getRequestedFields() { return requestedFields; } public Map> getTypeRemappings() { return typeRemappings; } public List getAdditionalDissectors() { return additionalDissectors; } public ApacheHttpdLogfileInputFormat() { super(); } public ApacheHttpdLogfileInputFormat( String logformat, Collection requestedFields, Map> typeRemappings, List additionalDissectors) { super(); this.logFormat = logformat; this.requestedFields.addAll(requestedFields); this.typeRemappings = typeRemappings; this.additionalDissectors = additionalDissectors; } // -------------------------------------------- public ApacheHttpdLogfileRecordReader createRecordReader() { try { return new ApacheHttpdLogfileRecordReader(getLogFormat(), getRequestedFields(), getTypeRemappings(), getAdditionalDissectors()); } catch (IOException e) { return null; } } public ApacheHttpdLogfileRecordReader getRecordReader() { if (theRecordReader == null) { theRecordReader = createRecordReader(); } return theRecordReader; } @Override public RecordReader createRecordReader( final InputSplit split, final TaskAttemptContext context) { return getRecordReader(); } @Override protected boolean isSplitable(JobContext context, Path file) { final CompressionCodec codec = new CompressionCodecFactory(context.getConfiguration()).getCodec(file); return (null == codec) || codec instanceof SplittableCompressionCodec; } public void setTypeRemappings(Map> newTypeRemappings) { this.typeRemappings = newTypeRemappings; } } ================================================ FILE: httpdlog/httpdlog-inputformat/src/main/java/nl/basjes/hadoop/input/ApacheHttpdLogfileRecordReader.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.hadoop.input; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.mapreduce.Counter; import org.apache.hadoop.mapreduce.InputSplit; import org.apache.hadoop.mapreduce.RecordReader; import org.apache.hadoop.mapreduce.TaskAttemptContext; import org.apache.hadoop.mapreduce.lib.input.LineRecordReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @SuppressWarnings({ "PMD.OnlyOneReturn", "PMD.BeanMembersShouldSerialize" }) public class ApacheHttpdLogfileRecordReader extends RecordReader { private static final Logger LOG = LoggerFactory.getLogger(ApacheHttpdLogfileRecordReader.class); private static final String HTTPD_LOGFILE_INPUT_FORMAT = "HTTPD Access Logfile InputFormat"; public static final String FIELDS = "fields"; // -------------------------------------------- private final LineRecordReader lineReader = new LineRecordReader(); private Parser parser; private List fieldList = null; private final ParsedRecord currentValue = new ParsedRecord(); private String logformat = null; private final Set requestedFields = new HashSet<>(); private Map> typeRemappings = new HashMap<>(16); private List additionalDissectors; // -------------------------------------------- @SuppressWarnings("unused") // Used by the Hadoop framework public ApacheHttpdLogfileRecordReader() { // Nothing to do here } public ApacheHttpdLogfileRecordReader(String logformat, Set requestedFields, Map> typeRemappings, List additionalDissectors) throws IOException { setLogFormat(logformat); // Mappings and additional parsers MUST come before the requested fields this.typeRemappings = typeRemappings; this.additionalDissectors = additionalDissectors; addRequestedFields(requestedFields); } private void addRequestedFields(Set newRequestedFields) throws IOException { requestedFields.addAll(newRequestedFields); fieldList = new ArrayList<>(requestedFields); try { setupFields(); } catch (NoSuchMethodException | MissingDissectorsException | InvalidDissectorException e) { throw new IOException("RecordReader initialization failed", e); } } private void setLogFormat(String newLogformat) { if (newLogformat == null) { return; } logformat = newLogformat; } private boolean outputAllPossibleFields = false; private String allPossiblePathsFieldName; private List allPossiblePaths = null; private Counter counterLinesRead; private Counter counterGoodLines; private Counter counterBadLines; @Override public void initialize(final InputSplit split, final TaskAttemptContext context) throws IOException { lineReader.initialize(split, context); final Configuration conf = context.getConfiguration(); counterLinesRead = context.getCounter(HTTPD_LOGFILE_INPUT_FORMAT, "1:Lines read"); counterGoodLines = context.getCounter(HTTPD_LOGFILE_INPUT_FORMAT, "2:Good lines"); counterBadLines = context.getCounter(HTTPD_LOGFILE_INPUT_FORMAT, "3:Bad lines"); if (logformat == null || requestedFields.isEmpty()) { if (logformat == null) { logformat = conf.get("nl.basjes.parse.apachehttpdlogline.format", "common"); } if (requestedFields.isEmpty()) { String fields = conf.get( "nl.basjes.parse.apachehttpdlogline.fields", null); if (fields != null) { fieldList = Arrays.asList(fields.split(",")); } } else { fieldList = new ArrayList<>(requestedFields); } } if (fieldList != null) { if (logformat != null && parser == null) { parser = createParser(); } for (String field : fieldList) { currentValue.declareRequestedFieldname(field); } } try { setupFields(); } catch (NoSuchMethodException | MissingDissectorsException | InvalidDissectorException e) { throw new IOException("RecordReader initialization failed", e); } } protected Parser instantiateParser(String logFormat) { return new HttpdLoglineParser<>(ParsedRecord.class, logFormat) .setTypeRemappings(typeRemappings) .addDissectors(additionalDissectors); } private Map> allCasts; private void setupFields() throws MissingDissectorsException, InvalidDissectorException, NoSuchMethodException, IOException { if (fieldList == null || fieldList.isEmpty()) { return; // Nothing to do here } String firstField = fieldList.get(0); if (fieldList.size() == 1 && firstField.toLowerCase().trim().equals(FIELDS)) { outputAllPossibleFields = true; allPossiblePaths = getParser().getPossiblePaths(); allPossiblePathsFieldName = firstField; Parser newParser = instantiateParser(logformat) .addParseTarget(ParsedRecord.class.getMethod("set", String.class, String.class), allPossiblePaths) .addTypeRemappings(typeRemappings); allCasts = newParser.getAllCasts(); } } public EnumSet getCasts(String name) throws IOException { if (outputAllPossibleFields) { return allCasts.get(name); } try { return getParser().getCasts(name); } catch (MissingDissectorsException | InvalidDissectorException e) { throw new IOException("Fatal error in the parser", e); } } public Parser getParser() throws IOException { if (parser == null) { parser = createParser(); } return parser; } private Parser createParser() throws IOException { if (fieldList == null || logformat == null) { return null; } Parser newParser; try { newParser = instantiateParser(logformat); for (String field: fieldList) { if (field.endsWith(".*")) { newParser.addParseTarget(ParsedRecord.class.getMethod("setMultiValueString", String.class, String.class), field); } else { newParser.addParseTarget(ParsedRecord.class.getMethod("set", String.class, String.class), field); newParser.addParseTarget(ParsedRecord.class.getMethod("set", String.class, Long.class), field); newParser.addParseTarget(ParsedRecord.class.getMethod("set", String.class, Double.class), field); } } } catch (NoSuchMethodException |SecurityException e) { throw new IOException(e.toString()); } return newParser; } // -------------------------------------------- private int errorLinesLogged = 0; private static final int MAX_ERROR_LINES_LOGGED = 10; @Override public boolean nextKeyValue() throws IOException { if (outputAllPossibleFields) { // We now ONLY return the possible names of the fields that can be requested if (allPossiblePaths.isEmpty()) { return false; } currentValue.clear(); String value = allPossiblePaths.get(0); allPossiblePaths.remove(0); currentValue.set(allPossiblePathsFieldName, value); return true; } else { boolean haveValue = false; while (!haveValue) { if (!lineReader.nextKeyValue()) { return false; } counterLinesRead.increment(1L); currentValue.clear(); String inputLine = lineReader.getCurrentValue().toString(); try { getParser().parse(currentValue, lineReader.getCurrentValue().toString()); counterGoodLines.increment(1L); haveValue = true; } catch (DissectionFailure e) { counterBadLines.increment(1L); if (errorLinesLogged < MAX_ERROR_LINES_LOGGED) { LOG.error("Parse error >>>{}<<< in line: >>>{}<<<", e.getMessage(), inputLine); errorLinesLogged++; if (errorLinesLogged == MAX_ERROR_LINES_LOGGED) { LOG.error(">>>>>>>>>>> We now stop logging parse errors! <<<<<<<<<<<"); } } // Ignore bad lines and simply continue } catch (InvalidDissectorException e) { LOG.error("InvalidDissectorException >>>{}<<<", e.getMessage()); return false; } catch (MissingDissectorsException e) { LOG.error("MissingDissectorsException >>>{}<<<", e.getMessage()); return false; } } } return true; } @Override public LongWritable getCurrentKey() { // The key we return is the same byte offset as the TextInputFormat // would give. return lineReader.getCurrentKey(); } @Override public ParsedRecord getCurrentValue() { return currentValue; } @Override public float getProgress() throws IOException { return lineReader.getProgress(); } // -------------------------------------------- @Override public void close() throws IOException { lineReader.close(); } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-inputformat/src/main/java/nl/basjes/hadoop/input/ParsedRecord.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.hadoop.input; import org.apache.hadoop.io.Writable; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class ParsedRecord implements Writable { private final Map stringValues = new HashMap<>(); private final Map longValues = new HashMap<>(); private final Map doubleValues = new HashMap<>(); private final Map> stringSetValues = new HashMap<>(); private final Map stringSetPrefixes = new HashMap<>(); @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof ParsedRecord)) { return false; } ParsedRecord that = (ParsedRecord) o; return stringValues.equals(that.stringValues) && longValues.equals(that.longValues) && doubleValues.equals(that.doubleValues) && stringSetPrefixes.equals(that.stringSetPrefixes) && stringSetValues.equals(that.stringSetValues); } @Override public int hashCode() { int result = stringValues.hashCode(); result = 31 * result + longValues.hashCode(); result = 31 * result + doubleValues.hashCode(); result = 31 * result + stringSetValues.hashCode(); return result; } @Override public void write(DataOutput out) throws IOException { out.writeInt(stringValues.size()); for (Map.Entry e : stringValues.entrySet()) { out.writeUTF(e.getKey()); out.writeUTF(e.getValue()); } out.writeInt(longValues.size()); for (Map.Entry e : longValues.entrySet()) { out.writeUTF(e.getKey()); out.writeLong(e.getValue()); } out.writeInt(doubleValues.size()); for (Map.Entry e : doubleValues.entrySet()) { out.writeUTF(e.getKey()); out.writeDouble(e.getValue()); } out.writeInt(stringSetPrefixes.size()); for (Map.Entry e : stringSetPrefixes.entrySet()) { out.writeUTF(e.getKey()); out.writeUTF(e.getValue()); } out.writeInt(stringSetValues.size()); for (Map.Entry> e : stringSetValues.entrySet()) { out.writeUTF(e.getKey()); out.writeInt(e.getValue().size()); for (Map.Entry s : e.getValue().entrySet()) { out.writeUTF(s.getKey()); out.writeUTF(s.getValue()); } } } @Override public void readFields(DataInput in) throws IOException { // String int nrOfValues = in.readInt(); for (int count = 0; count < nrOfValues; count++) { stringValues.put(in.readUTF(), in.readUTF()); } // Long nrOfValues = in.readInt(); for (int count = 0; count < nrOfValues; count++) { longValues.put(in.readUTF(), in.readLong()); } // Double nrOfValues = in.readInt(); for (int count = 0; count < nrOfValues; count++) { doubleValues.put(in.readUTF(), in.readDouble()); } // String Prefixes nrOfValues = in.readInt(); for (int count = 0; count < nrOfValues; count++) { stringSetPrefixes.put(in.readUTF(), in.readUTF()); } // String Map int nrOfFields = in.readInt(); for (int fieldNr = 0; fieldNr < nrOfFields; fieldNr++) { String fieldName = in.readUTF(); nrOfValues = in.readInt(); Map values = new HashMap<>(nrOfValues); for (int valueNr = 0; valueNr < nrOfValues; valueNr++) { String key = in.readUTF(); String value = in.readUTF(); values.put(key, value); } stringSetValues.put(fieldName, values); } } public ParsedRecord() { } public void clear() { stringValues.clear(); longValues.clear(); doubleValues.clear(); for (Map.Entry> stringMap : stringSetValues.entrySet()) { stringMap.getValue().clear(); } } public void set(String name, String value) { if (value != null) { stringValues.put(name, value); } } public void set(String name, Long value) { if (value != null) { longValues.put(name, value); } } public void set(String name, Double value) { if (value != null) { doubleValues.put(name, value); } } /** * For multivalue things we need to know what the name is we are expecting. * For those patterns we match the values we get against * * @param name the name of the requested multivalue */ public void declareRequestedFieldname(String name) { if (name.endsWith(".*")) { stringSetValues.put(name, new HashMap<>()); stringSetPrefixes.put(name.substring(0, name.length() - 1), name); } } public void setMultiValueString(String name, String value) { if (value != null) { for (Map.Entry stringSetPrefix : stringSetPrefixes.entrySet()) { String prefix = stringSetPrefix.getKey(); if (name.startsWith(prefix)) { stringSetValues .get(stringSetPrefix.getValue()) .put(name.substring(prefix.length()), value); } } } } public String getString(String name) { return stringValues.get(name); } public Long getLong(String name) { return longValues.get(name); } public Double getDouble(String name) { return doubleValues.get(name); } public Map getStringSet(String name) { return stringSetValues.get(name); } } ================================================ FILE: httpdlog/httpdlog-inputformat/src/test/java/nl/basjes/hadoop/input/TestApacheHttpdLogfileInputFormat.java ================================================ package nl.basjes.hadoop.input; /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.test.NormalValuesDissector; import nl.basjes.parse.httpdlog.HttpdLogFormatDissector; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.mapreduce.InputFormat; import org.apache.hadoop.mapreduce.RecordReader; import org.apache.hadoop.mapreduce.TaskAttemptContext; import org.apache.hadoop.mapreduce.TaskAttemptID; import org.apache.hadoop.mapreduce.lib.input.FileSplit; import org.apache.hadoop.mapreduce.task.TaskAttemptContextImpl; import org.apache.hadoop.util.ReflectionUtils; import org.junit.jupiter.api.Test; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; class TestApacheHttpdLogfileInputFormat { // CHECKSTYLE.OFF: LineLength final String logformat = "%h %l %u %t \"%r\" %>s %O \"%{%D %F %R %T %r %a %A %b %B %C %d %G %h %H %I %j %k %l %m %M %p %S %u %Y %z}t\" \"%{User-Agent}i\""; // CHECKSTYLE.ON: LineLength @Test void checkInputFormat() throws IOException, InterruptedException { Configuration conf = new Configuration(false); conf.set("fs.default.name", "file:///"); conf.set("nl.basjes.parse.apachehttpdlogline.format", logformat); // A ',' separated list of fields conf.set("nl.basjes.parse.apachehttpdlogline.fields", "TIME.EPOCH:request.receive.time.epoch," + "HTTP.USERAGENT:request.user-agent"); File testFile = new File("src/test/resources/access.log"); Path path = new Path(testFile.getAbsoluteFile().toURI()); FileSplit split = new FileSplit(path, 0, testFile.length(), null); InputFormat inputFormat = ReflectionUtils.newInstance(ApacheHttpdLogfileInputFormat.class, conf); TaskAttemptContext context = new TaskAttemptContextImpl(conf, new TaskAttemptID()); RecordReader reader = inputFormat.createRecordReader(split, context); reader.initialize(split, context); assertTrue(reader.nextKeyValue()); ParsedRecord value = reader.getCurrentValue(); assertEquals("1483272081000", value.getString("TIME.EPOCH:request.receive.time.epoch")); assertEquals("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36", value.getString("HTTP.USERAGENT:request.user-agent")); } @Test void checkAllOutputTypes() throws IOException, InterruptedException { Configuration conf = new Configuration(false); conf.set("fs.default.name", "file:///"); // A ',' separated list of fields List fields = Arrays.asList( "ANY:any", "ANY:any", "ANY:any", "STRING:string", "STRING:string", "STRING:string", "INT:int", "INT:int", "INT:int", "LONG:long", "LONG:long", "LONG:long", "FLOAT:float", "FLOAT:float", "FLOAT:float", "DOUBLE:double", "DOUBLE:double", "DOUBLE:double"); File testFile = new File("src/test/resources/access.log"); Path path = new Path(testFile.getAbsoluteFile().toURI()); FileSplit split = new FileSplit(path, 0, testFile.length(), null); Map> typeRemappings = new HashMap<>(); List dissectors = new ArrayList<>(); dissectors.add(new NormalValuesDissector(HttpdLogFormatDissector.INPUT_TYPE)); InputFormat inputFormat = new ApacheHttpdLogfileInputFormat( logformat, fields, typeRemappings, dissectors); TaskAttemptContext context = new TaskAttemptContextImpl(conf, new TaskAttemptID()); RecordReader reader = inputFormat.createRecordReader(split, context); reader.initialize(split, context); assertTrue(reader.nextKeyValue()); ParsedRecord value = reader.getCurrentValue(); assertEquals("42", value.getString("ANY:any")); // any_string assertEquals(42L, value.getLong("ANY:any").longValue()); // any_long assertEquals(42D, value.getDouble("ANY:any"), 0.1D); // any_double assertEquals("FortyTwo", value.getString("STRING:string")); // string_string assertEquals(null, value.getLong("STRING:string")); // string_long assertEquals(null, value.getDouble("STRING:string")); // string_double assertEquals("42", value.getString("INT:int")); // int_string assertEquals(42L, value.getLong("INT:int").longValue()); // int_long assertEquals(null, value.getDouble("INT:int")); // int_double assertEquals("42", value.getString("LONG:long")); // long_string assertEquals(42L, value.getLong("LONG:long").longValue()); // long_long assertEquals(null, value.getDouble("LONG:long")); // long_double assertEquals("42.0", value.getString("FLOAT:float")); // float_string assertEquals(null, value.getLong("FLOAT:float")); // float_long assertEquals(42D, value.getDouble("FLOAT:float"), 0.1D); // float_double assertEquals("42.0", value.getString("DOUBLE:double")); // double_string assertEquals(null, value.getLong("DOUBLE:double")); // double_long assertEquals(42D, value.getDouble("DOUBLE:double"), 0.1D); // double_double } } ================================================ FILE: httpdlog/httpdlog-inputformat/src/test/java/nl/basjes/hadoop/input/TestGetAllFields.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.hadoop.input; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.mapreduce.RecordReader; import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import static org.junit.jupiter.api.Assertions.assertTrue; class TestGetAllFields { @Test void testGetAllField() throws IOException, InterruptedException { ApacheHttpdLogfileInputFormat inputFormat = new ApacheHttpdLogfileInputFormat( "common", Collections.singleton(ApacheHttpdLogfileRecordReader.FIELDS), Collections.emptyMap(), Collections.emptyList()); RecordReader reader = inputFormat.getRecordReader(); Set possibleFields = new HashSet<>(100); while (reader.nextKeyValue()){ ParsedRecord currentValue = reader.getCurrentValue(); String value = currentValue.getString(ApacheHttpdLogfileRecordReader.FIELDS); if (value == null) { continue; } possibleFields.add(value); } assertTrue(possibleFields.containsAll(Arrays.asList( // A subset of all fields that come out "STRING:connection.client.user", "IP:connection.client.host.last", "TIME.STAMP:request.receive.time.last", "TIME.EPOCH:request.receive.time.epoch", "STRING:request.status.last", "STRING:connection.client.user.last", "HTTP.METHOD:request.firstline.original.method", "HTTP.URI:request.firstline.uri", "HTTP.PATH:request.firstline.uri.path", "HTTP.QUERYSTRING:request.firstline.uri.query", "STRING:request.firstline.uri.query.*", "BYTES:response.body.bytesclf", "BYTESCLF:response.body.bytesclf", "IP:connection.client.host"))); } @Test void checkPossibleFields(){ List possibleFields = new ApacheHttpdLogfileInputFormat().listPossibleFields("common"); assertTrue(possibleFields.containsAll(Arrays.asList( // A subset of all fields that come out "STRING:connection.client.user", "IP:connection.client.host.last", "TIME.STAMP:request.receive.time.last", "TIME.EPOCH:request.receive.time.epoch", "STRING:request.status.last", "STRING:connection.client.user.last", "HTTP.METHOD:request.firstline.original.method", "HTTP.URI:request.firstline.uri", "HTTP.PATH:request.firstline.uri.path", "HTTP.QUERYSTRING:request.firstline.uri.query", "STRING:request.firstline.uri.query.*", "BYTES:response.body.bytesclf", "BYTESCLF:response.body.bytesclf", "IP:connection.client.host"))); } } ================================================ FILE: httpdlog/httpdlog-inputformat/src/test/java/nl/basjes/hadoop/input/TestParsedRecord.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.hadoop.input; import org.apache.commons.io.IOUtils; import org.apache.hadoop.io.Writable; import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class TestParsedRecord { // Copied from https://stackoverflow.com/questions/13288214/how-to-unit-test-hadoop-writable public static byte[] serialize(Writable writable) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); DataOutputStream dataOut = null; try { dataOut = new DataOutputStream(out); writable.write(dataOut); return out.toByteArray(); } finally { IOUtils.closeQuietly(dataOut); } } public static T asWritable(byte[] bytes, Class clazz) throws IOException, IllegalAccessException, InstantiationException { T result; DataInputStream dataIn = null; try { result = clazz.newInstance(); ByteArrayInputStream in = new ByteArrayInputStream(bytes); dataIn = new DataInputStream(in); result.readFields(dataIn); } finally { IOUtils.closeQuietly(dataIn); } return result; } @SuppressWarnings({"EqualsBetweenInconvertibleTypes", "ObjectEqualsNull", "EqualsWithItself"}) @Test void testParsedRecordSerialization() throws IOException, InstantiationException, IllegalAccessException { ParsedRecord record = new ParsedRecord(); // Set and verify setAllValues(record); checkAllValues(record); byte[] serializedBytes = serialize(record); ParsedRecord deserialized = asWritable(serializedBytes, ParsedRecord.class); // Compare both before and after records checkAllValues(record); checkAllValues(deserialized); assertTrue(record.equals(deserialized), "Equals failed!"); assertTrue(record.equals(record), "Equals failed!"); assertFalse(record.equals(null), "Equals failed!"); assertFalse(record.equals(this), "Equals failed!"); assertEquals(record.hashCode(), deserialized.hashCode(), "Hashcode is different!"); record.clear(); } private void setAllValues(ParsedRecord record) { record.set("String A", "42"); record.set("String B", "42"); record.set("String C", "42"); record.set("String D", "42"); record.set("Long A", 42L); record.set("Long B", 42L); record.set("Long C", 42L); record.set("Long D", 42L); record.set("Double A", 42D); record.set("Double B", 42D); record.set("Double C", 42D); record.set("Double D", 42D); record.declareRequestedFieldname("Multi_A.*"); record.setMultiValueString("Multi_A.1", "Foo"); record.setMultiValueString("Multi_A.2", "Bar"); record.declareRequestedFieldname("Multi_B.*"); record.setMultiValueString("Multi_B.1", "Foo"); record.setMultiValueString("Multi_B.2", "Bar"); record.declareRequestedFieldname("Multi_C.*"); record.setMultiValueString("Multi_C.1", "Foo"); record.setMultiValueString("Multi_C.2", "Bar"); } private void checkAllValues(ParsedRecord record) { assertEquals("42", record.getString("String A"), "String A"); assertEquals("42", record.getString("String B"), "String B"); assertEquals("42", record.getString("String C"), "String C"); assertEquals("42", record.getString("String D"), "String D"); assertEquals((Long)42L, record.getLong("Long A"), "Long A"); assertEquals((Long)42L, record.getLong("Long B"), "Long B"); assertEquals((Long)42L, record.getLong("Long C"), "Long C"); assertEquals((Long)42L, record.getLong("Long D"), "Long D"); assertEquals((Double)42D, record.getDouble("Double A"), "Double A"); assertEquals((Double)42D, record.getDouble("Double B"), "Double B"); assertEquals((Double)42D, record.getDouble("Double C"), "Double C"); assertEquals((Double)42D, record.getDouble("Double D"), "Double D"); assertEquals("Foo", record.getStringSet("Multi_A.*").get("1"), "Multi_A.* --> 1"); assertEquals("Bar", record.getStringSet("Multi_A.*").get("2"), "Multi_A.* --> 2"); assertEquals("Foo", record.getStringSet("Multi_B.*").get("1"), "Multi_B.* --> 1"); assertEquals("Bar", record.getStringSet("Multi_B.*").get("2"), "Multi_B.* --> 2"); assertEquals("Foo", record.getStringSet("Multi_C.*").get("1"), "Multi_C.* --> 1"); assertEquals("Bar", record.getStringSet("Multi_C.*").get("2"), "Multi_C.* --> 2"); } } ================================================ FILE: httpdlog/httpdlog-inputformat/src/test/resources/access.log ================================================ 127.0.0.1 - - [01/Jan/2017:13:01:21 +0100] "GET / HTTP/1.1" 200 3525 "01/01/17 2017-01-01 13:01 13:01:21 01:01:21 PM Sun Sunday Jan January 20 01 2016 Jan 13 01 001 13 1 01 01 PM 21 7 2017 +0100" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36" ================================================ FILE: httpdlog/httpdlog-inputformat/src/test/resources/log4j.properties ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Root logger option log4j.rootLogger=INFO, stdout #, file log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.threshold=INFO log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n ## file appender #log4j.appender.file=org.apache.log4j.RollingFileAppender #log4j.appender.file.File=target/debug.log #log4j.appender.file.threshold=DEBUG #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n #log4j.appender.file.Append=false ================================================ FILE: httpdlog/httpdlog-parser/pom.xml ================================================ 4.0.0 httpdlog nl.basjes.parse.httpdlog 6.0.1-SNAPSHOT httpdlog-parser Parser - Apache HTTPD - Parser https://niels.basjes.nl 4.13.2 2.21.3 2.21 nl.basjes.parse parser-core ${project.version} nl.basjes.parse parser-core ${project.version} tests test commons-codec commons-codec 1.22.0 org.antlr antlr4-runtime ${antlr.version} com.maxmind.geoip2 geoip2 5.1.0 commons-codec commons-codec com.fasterxml.jackson.core jackson-core com.fasterxml.jackson.core jackson-databind com.fasterxml.jackson.core jackson-annotations com.fasterxml.jackson.core jackson-core ${jackson.version} com.fasterxml.jackson.core jackson-databind ${jackson.version} com.fasterxml.jackson.core jackson-annotations ${jackson-annotations.version} src/main/resources version/* org.jacoco jacoco-maven-plugin nl/basjes/parse/httpdlog/Version.class nl/basjes/parse/strftime/*.class com.google.code.maven-replacer-plugin replacer 1.5.3 generate-sources replace ${basedir}/src/main/resources/version/Version.java.template ${basedir}/target/generated-sources/java/nl/basjes/parse/httpdlog/Version.java @git.commit.id.describe-short@ ${git.commit.id.describe-short} @project.build.outputTimestamp@ ${project.build.outputTimestamp} @project.version@ ${project.version} org.codehaus.mojo build-helper-maven-plugin 3.6.1 add-source generate-sources add-source ${project.build.directory}/generated-sources/java/ org.apache.maven.plugins maven-shade-plugin true org.antlr:antlr4-runtime META-INF/services/** META-INF/MANIFEST.MF org.apache.commons:commons-text META-INF/MANIFEST.MF META-INF/versions/9/module-info.class org.apache.commons:commons-lang3 META-INF/MANIFEST.MF org.antlr ${project.groupId}.${project.artifactId}.shaded.org.antlr org.apache.commons.text ${project.groupId}.${project.artifactId}.shaded.org.apache.commons.text org.apache.commons.lang3 ${project.groupId}.${project.artifactId}.shaded.org.apache.commons.lang3 inject-problematic-dependencies package shade org.antlr:antlr4-runtime org.apache.commons:commons-text org.apache.commons:commons-lang3 org.apache.maven.plugins maven-clean-plugin ${project.basedir} dependency-reduced-pom.xml org.antlr antlr4-maven-plugin ${antlr.version} antlr antlr4 ================================================ FILE: httpdlog/httpdlog-parser/src/main/antlr4/nl/basjes/parse/strftime/StrfTime.g4 ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ grammar StrfTime; // Comments copied from the strftime man 3 page. // See: http://man7.org/linux/man-pages/man3/strftime.3.html // %E Modifier: use alternative format, see below. // %O Modifier: use alternative format, see below. // Some conversion specifications can be modified by preceding the // conversion specifier character by the E or O modifier to indicate // that an alternative format should be used. If the alternative format // or specification does not exist for the current locale, the behavior // will be as if the unmodified conversion specification were used. // The Single UNIX Specification mentions %Ec, %EC, %Ex, %EX, %Ey, %EY, // %Od, %Oe, %OH, %OI, %Om, %OM, %OS, %Ou, %OU, %OV, %Ow, %OW, %Oy, // where the effect of the O modifier is to use alternative numeric // symbols (say, roman numerals), and that of the E modifier is to use a // locale-dependent alternative representation. // We are simply ignoring all of these modifiers fragment MOD: ( 'E' | 'O' )?; MsecFrac : '%'? 'msec_frac' ; // Apache HTTPD specific: milliseconds fraction UsecFrac : '%'? 'usec_frac' ; // Apache HTTPD specific: microseconds fraction Pa : '%' MOD 'a' ; // The abbreviated name of the day of the week according to the current locale. PA : '%' MOD 'A' ; // The full name of the day of the week according to the current locale. Pb : '%' MOD 'b' ; // The abbreviated month name according to the current locale. Ph : '%' MOD 'h' ; // Equivalent to %b. PB : '%' MOD 'B' ; // The full month name according to the current locale. Pc : '%' MOD 'c' ; // The preferred date and time representation for the current locale. PC : '%' MOD 'C' ; // The century number (year/100) as a 2-digit integer. Pd : '%' MOD 'd' ; // The day of the month as a decimal number (range 01 to 31). PD : '%' MOD 'D' ; // Equivalent to %m/%d/%y. (Yecch—for Americans only) Pe : '%' MOD 'e' ; // Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. PF : '%' MOD 'F' ; // Equivalent to %Y-%m-%d (the ISO 8601 date format). PG : '%' MOD 'G' ; // The ISO 8601 week-based year (see NOTES) with century as a decimal number. The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %Y, except that if the ISO week number belongs to the previous or next year, that year is used instead. Pg : '%' MOD 'g' ; // Like %G, but without century, that is, with a 2-digit year (00–99). PH : '%' MOD 'H' ; // The hour as a decimal number using a 24-hour clock (range 00 to 23). PI : '%' MOD 'I' ; // The hour as a decimal number using a 12-hour clock (range 01 to 12). Pj : '%' MOD 'j' ; // The day of the year as a decimal number (range 001 to 366). Pk : '%' MOD 'k' ; // The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H) Pl : '%' MOD 'l' ; // The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. (See also %I) Pm : '%' MOD 'm' ; // The month as a decimal number (range 01 to 12). PM : '%' MOD 'M' ; // The minute as a decimal number (range 00 to 59). Pp : '%' MOD 'p' ; // Either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale. Noon is treated as "PM" and midnight as "AM". PP : '%' MOD 'P' ; // Like %p but in lowercase: "am" or "pm" or a corresponding string for the current locale. Pr : '%' MOD 'r' ; // The time in a.m. or p.m. notation. In the POSIX locale this is equivalent to %I:%M:%S %p. PR : '%' MOD 'R' ; // The time in 24-hour notation (%H:%M). For a version including the seconds, see %T below. Ps : '%' MOD 's' ; // The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). PS : '%' MOD 'S' ; // The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds) PT : '%' MOD 'T' ; // The time in 24-hour notation (%H:%M:%S). Pu : '%' MOD 'u' ; // The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. PU : '%' MOD 'U' ; // The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01. See also %V and %W. PV : '%' MOD 'V' ; // The ISO 8601 week number (see NOTES) of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the new year. See also %U and %W. Pw : '%' MOD 'w' ; // The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u. PW : '%' MOD 'W' ; // The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01. Px : '%' MOD 'x' ; // The preferred date representation for the current locale without the time. PX : '%' MOD 'X' ; // The preferred time representation for the current locale without the date. Py : '%' MOD 'y' ; // The year as a decimal number without a century (range 00 to 99). PY : '%' MOD 'Y' ; // The year as a decimal number including the century. Pz : '%' MOD 'z' ; // The +hhmm or -hhmm numeric timezone. PZ : '%' MOD 'Z' ; // The timezone name or abbreviation. Pplus : '%' MOD '+' ; // The date and time in date(1) format. Pt : '%t' ; // A tab character. Pn : '%n' ; // A newline character. PERCENT : '%%' ; // A literal '%' character. LITERAL : ~('%'); pattern : (literal|token)+ ; literal : text | tab | percent | newline ; text: LITERAL ; tab : Pt ; percent : PERCENT ; newline : Pn ; token : pa | pA | pb | pB | pc | pC | pd | pD | pe | pF | pG | pg | pH | pI | pj | pk | pl | pm | pM | pp | pP | pr | pR | ps | pS | pT | pu | pU | pV | pw | pW | px | pX | py | pY | pz | pZ | pplus | msecFrac | usecFrac ; msecFrac : MsecFrac ; // Apache HTTPD specific: milliseconds fraction usecFrac : UsecFrac ; // Apache HTTPD specific: microseconds fraction pa : Pa ; pA : PA ; pb : Pb | Ph ; pB : PB ; pc : Pc ; pC : PC ; pd : Pd ; pD : PD ; pe : Pe ; pF : PF ; pG : PG ; pg : Pg ; pH : PH ; pI : PI ; pj : Pj ; pk : Pk ; pl : Pl ; pm : Pm ; pM : PM ; pp : Pp ; pP : PP ; pr : Pr ; pR : PR ; ps : Ps ; pS : PS ; pT : PT ; pu : Pu ; pU : PU ; pV : PV ; pw : Pw ; pW : PW ; px : Px ; pX : PX ; py : Py ; pY : PY ; pz : Pz ; pZ : PZ ; pplus : Pplus ; ================================================ FILE: httpdlog/httpdlog-parser/src/main/assembly/job.xml ================================================ job jar false false lib false compile ${project.build.outputDirectory} ${file.separator} ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/ApacheHttpdLogFormatDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Casts; import nl.basjes.parse.httpdlog.dissectors.HttpFirstLineDissector; import nl.basjes.parse.httpdlog.dissectors.StrfTimeStampDissector; import nl.basjes.parse.httpdlog.dissectors.tokenformat.NamedTokenParser; import nl.basjes.parse.httpdlog.dissectors.tokenformat.ParameterizedTokenParser; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenFormatDissector; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenOutputField; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_CLF_HEXNUMBER; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_CLF_IP; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_CLF_NUMBER; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NO_SPACE_STRING; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NUMBER; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STANDARD_TIME_US; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STRING; @SuppressWarnings({ "PMD.LongVariable", // I like my variable names this way "PMD.CyclomaticComplexity", "PMD.OnlyOneReturn", "PMD.BeanMembersShouldSerialize", // No beans here "PMD.DataflowAnomalyAnalysis" // Results in a lot of mostly useless messages. }) public class ApacheHttpdLogFormatDissector extends TokenFormatDissector { private static final Logger LOG = LoggerFactory.getLogger(ApacheHttpdLogFormatDissector.class); public ApacheHttpdLogFormatDissector(final String logFormat) { super(logFormat); setInputType(HttpdLogFormatDissector.INPUT_TYPE); } public ApacheHttpdLogFormatDissector() { super(); setInputType(HttpdLogFormatDissector.INPUT_TYPE); } private void overrideLogFormat(String originalLogformat, String logformat){ LOG.debug("Specified logformat \"{}\" was mapped to {}", originalLogformat, logformat); super.setLogFormat(logformat); } @Override public void setLogFormat(final String logformat) { // Commonly used logformats as documented in the manuals of the Apache Httpd // LogFormat "%h %l %u %t \"%r\" %>s %b" common // LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined // LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio // LogFormat "%{Referer}i -> %U" referer // LogFormat "%{User-agent}i" agent switch (logformat.toLowerCase(Locale.getDefault())) { case "common": overrideLogFormat(logformat, "%h %l %u %t \"%r\" %>s %b"); break; case "combined": overrideLogFormat(logformat, "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""); break; case "combinedio": overrideLogFormat(logformat, "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O"); break; case "referer": overrideLogFormat(logformat, "%{Referer}i -> %U"); break; case "agent": overrideLogFormat(logformat, "%{User-agent}i"); break; default: super.setLogFormat(logformat); break; } } public static boolean looksLikeApacheFormat(String logFormat) { if (logFormat.indexOf('%') != -1) { return true; } switch (logFormat.toLowerCase(Locale.getDefault())) { case "common": case "combined": case "combinedio": case "referer": case "agent": return true; default: return false; } } // -------------------------------------------- protected String makeHeaderNamesLowercaseInLogFormat(String logformat) { // In vim I would simply do: %s@{\([^}]*\)}@{\L\1\E@g // But such an expression is not (yet) possible in Java StringBuffer sb = new StringBuffer(logformat.length()); // All patterns that have a 'name' (note we do NOT do it to %{...}t ) Pattern p = Pattern.compile("%\\{([^}]*)}([^t])"); Matcher m = p.matcher(logformat); while (m.find()) { m.appendReplacement(sb, "%{"+m.group(1).toLowerCase()+'}'+m.group(2)); } m.appendTail(sb); return sb.toString(); } protected String removeModifiersFromLogformat(String tokenLogFormat) { // Modifiers // Particular items can be restricted to print only for responses with specific HTTP status codes // by placing a comma-separated list of status codes immediately following the "%". // The status code list may be preceded by a "!" to indicate negation. // // %400,501{User-agent}i Logs User-agent on 400 errors and 501 errors only. // For other status codes, the literal string "-" will be logged. // %!200,304,302{Referer}i Logs Referer on all requests that do not return one of the three // specified codes, "-" otherwise. return tokenLogFormat.replaceAll("%!?[0-9]{3}(?:,[0-9]{3})*", "%"); } protected String fixTimestampFormat(String tokenLogFormat) { // The %t is mapped to the actual time format surrounded by '[' ']' // We generate the [] around it and in the rest of the parsing // work with the clean format. // This is mainly needed to ensure reuse in conjunction with Nginx parsing. // NOTE: The %{...}t time format does NOT get the automatic '[' ']' around it. return tokenLogFormat.replaceAll("%t", "[%t]"); } @Override protected String cleanupLogFormat(String tokenLogFormat) { String result = removeModifiersFromLogformat(tokenLogFormat); result = makeHeaderNamesLowercaseInLogFormat(result); result = fixTimestampFormat(result); return result; } @Override public String decodeExtractedValue(String tokenName, String value) { if (value == null || value.equals("")) { return value; } // In Apache logfiles a '-' means a 'not specified' / 'empty' value. if (value.equals("-")){ return null; } // http://httpd.apache.org/docs/current/mod/mod_log_config.html#formats // Format Notes // For security reasons, starting with version 2.0.46, non-printable and other special characters // in %r, %i and %o are escaped using \xhh sequences, where hh stands for the hexadecimal representation of // the raw byte. Exceptions from this rule are " and \, which are escaped by prepending a backslash, and // all whitespace characters, which are written in their C-style notation (\n, \t, etc). // In versions prior to 2.0.46, no escaping was performed on these strings so you had to be quite careful // when dealing with raw log files. if (tokenName.equals("request.firstline") || // %r First line of request. tokenName.equals("request.user-agent") || // %{User-Agent}i The contents of the User-Agent request header. tokenName.equals("request.user-agent.last") || // %{User-Agent}i The contents of the User-Agent request header. tokenName.startsWith("request.header.") || // %{Foobar}i The contents of Foobar: request header line(s). tokenName.startsWith("response.header.")) { // %{Foobar}o The contents of Foobar: response header line(s). return Utils.decodeApacheHTTPDLogValue(value); } return value; } // -------------------------------------------- @Override protected List createAllTokenParsers() { List parsers = new ArrayList<>(60); // Quote from // http://httpd.apache.org/docs/current/mod/mod_log_config.html#logformat // Format String Description // ------- // %% The percent sign parsers.add(new FixedStringTokenParser("%%", "%")); // ------- // %a Remote IP-address parsers.addAll(createFirstAndLastTokenParsers("%a", "connection.client.ip", "IP", STRING_ONLY, FORMAT_CLF_IP)); // %{c}a Underlying peer IP address of the connection (see the mod_remoteip module). parsers.addAll(createFirstAndLastTokenParsers("%{c}a", "connection.client.peerip", "IP", STRING_ONLY, FORMAT_CLF_IP)); // ------- // %A Local IP-address parsers.addAll(createFirstAndLastTokenParsers("%A", "connection.server.ip", "IP", STRING_ONLY, FORMAT_CLF_IP)); // ------- // %B Size of response in bytes, excluding HTTP headers. parsers.addAll(createFirstAndLastTokenParsers("%B", "response.body.bytes", "BYTES", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %b Size of response in bytes, excluding HTTP headers. In CLF format, // i.e. a '-' rather than a 0 when no bytes are sent. parsers.addAll(createFirstAndLastTokenParsers("%b", "response.body.bytes", "BYTESCLF", STRING_OR_LONG, FORMAT_CLF_NUMBER)); // Additional support for the deprecated old output addExtraOutput(parsers, "%b", new TokenOutputField("BYTES", "response.body.bytesclf", STRING_OR_LONG) .deprecateFor("BYTESCLF:response.body.bytes")); // ------- // %{Foobar}C The contents of cookie Foobar in the request sent to the server. parsers.add(new NamedTokenParser("\\%\\{([a-z0-9\\-_]*)\\}C", "request.cookies.", "HTTP.COOKIE", STRING_ONLY, FORMAT_STRING)); // ------- // %{FOOBAR}e The contents of the environment variable FOOBAR parsers.add(new NamedTokenParser("\\%\\{([a-z0-9\\-_]*)\\}e", "server.environment.", "VARIABLE", STRING_ONLY, FORMAT_STRING)); // ------- // %f Filename parsers.addAll(createFirstAndLastTokenParsers("%f", "server.filename", "FILENAME", STRING_ONLY, FORMAT_STRING)); // ------- // %h Remote host parsers.addAll(createFirstAndLastTokenParsers("%h", "connection.client.host", "IP", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %H The request protocol parsers.addAll(createFirstAndLastTokenParsers("%H", "request.protocol", "PROTOCOL", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %{Foobar}i The contents of Foobar: header line(s) in the request sent // to the server. Changes made by other modules (e.g. mod_headers) // affect this. parsers.add(new NamedTokenParser("\\%\\{([a-z0-9\\-_]*)\\}i", "request.header.", "HTTP.HEADER", STRING_ONLY, FORMAT_STRING)); // ------- // %{VARNAME}^ti The contents of VARNAME: trailer line(s) in the request sent to the server. parsers.add(new NamedTokenParser("\\%\\{([a-z0-9\\-_]*)\\}\\^ti", "request.trailer.", "HTTP.TRAILER", STRING_ONLY, FORMAT_STRING)); // ------- // %k Number of keepalive requests handled on this connection. // Interesting if KeepAlive is being used, so that, for example, // a '1' means the first keepalive request after the initial one, ' // 2' the second, etc...; // otherwise this is always 0 (indicating the initial request). // Available in versions 2.2.11 and later. parsers.addAll(createFirstAndLastTokenParsers("%k", "connection.keepalivecount", "NUMBER", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %l Remote logname (from identd, if supplied). This will return a dash // unless mod_ident is present and IdentityCheck is set On. parsers.addAll(createFirstAndLastTokenParsers("%l", "connection.client.logname", "NUMBER", STRING_OR_LONG, FORMAT_CLF_NUMBER)); // ------- // %L The request log ID from the error log (or '-' if nothing has been logged to the error log for this request). // Look for the matching error log line to see what request caused what error. parsers.addAll(createFirstAndLastTokenParsers("%L", "request.errorlogid", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %m The request method parsers.addAll(createFirstAndLastTokenParsers("%m", "request.method", "HTTP.METHOD", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %{Foobar}n The contents of note Foobar from another module. parsers.add(new NamedTokenParser("\\%\\{([a-z0-9\\-_]*)\\}n", "server.module_note.", "STRING", STRING_ONLY, FORMAT_STRING)); // ------- // %{Foobar}o The contents of Foobar: header line(s) in the response. parsers.add(new NamedTokenParser("\\%\\{([a-z0-9\\-]*)\\}o", "response.header.", "HTTP.HEADER", STRING_ONLY, FORMAT_STRING)); // ------- // %{VARNAME}^to The contents of VARNAME: trailer line(s) in the response sent from the server. parsers.add(new NamedTokenParser("\\%\\{([a-z0-9\\-_]*)\\}\\^to", "response.trailer.", "HTTP.TRAILER", STRING_ONLY, FORMAT_STRING)); // ------- // %p The canonical port of the server serving the request parsers.addAll(createFirstAndLastTokenParsers("%p", "request.server.port.canonical", "PORT", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %{format}p The canonical port of the server serving the request or // the server's actual port or the client's actual port. Valid formats // are canonical, local, or remote. parsers.addAll(createFirstAndLastTokenParsers("%{canonical}p", "connection.server.port.canonical", "PORT", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{local}p", "connection.server.port", "PORT", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{remote}p", "connection.client.port", "PORT", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %P The process ID of the child that serviced the request. parsers.addAll(createFirstAndLastTokenParsers("%P", "connection.server.child.processid", "NUMBER", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %{format}P The process ID or thread id of the child that serviced the // request. Valid formats are pid, tid, and hextid. hextid requires // APR 1.2.0 or higher. parsers.addAll(createFirstAndLastTokenParsers("%{pid}P", "connection.server.child.processid", "NUMBER", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{tid}P", "connection.server.child.threadid", "NUMBER", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{hextid}P", "connection.server.child.hexthreadid", "NUMBER", STRING_OR_LONG, FORMAT_CLF_HEXNUMBER)); // ------- // %q The query string (prepended with a ? if a query string exists, // otherwise an empty string) parsers.addAll(createFirstAndLastTokenParsers("%q", "request.querystring", "HTTP.QUERYSTRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %r First line of request parsers.addAll(createFirstAndLastTokenParsers("%r", "request.firstline", "HTTP.FIRSTLINE", STRING_ONLY, HttpFirstLineDissector.FIRSTLINE_REGEX)); // ------- // %R The handler generating the response (if any). parsers.addAll(createFirstAndLastTokenParsers("%R", "request.handler", "STRING", STRING_ONLY, FORMAT_STRING)); // ------- // %s Status. For requests that got internally redirected, this is the // status of the *original* request --- %>s for the last. parsers.addAll(createFirstAndLastTokenParsers("%s", "request.status", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING, 0)); // ------- // %t Time the request was received (standard english format) parsers.addAll(createFirstAndLastTokenParsers("%t", "request.receive.time", "TIME.STAMP", STRING_ONLY, FORMAT_STANDARD_TIME_US)); // %{format}t The time, in the form given by format, which should be in // strftime(3) format. (potentially localized) parsers.add(new ParameterizedTokenParser("\\%\\{([^\\}]*%[^\\}]*)\\}t", "request.receive.time", "TIME.STRFTIME_", STRING_ONLY, FORMAT_STRING, -1, new StrfTimeStampDissector()) .setWarningMessageWhenUsed("Only some parts of localized timestamps are supported") ); // If the format starts with begin: (default) the time is taken at the beginning of the request processing. // If it starts with end: it is the time when the log entry gets written, close to the end of the request processing. parsers.add(new ParameterizedTokenParser("\\%\\{begin:([^\\}]*%[^\\}]*)\\}t", "request.receive.time.begin", "TIME.STRFTIME_", STRING_ONLY, FORMAT_STRING, 0, new StrfTimeStampDissector()) .setWarningMessageWhenUsed("Only some parts of localized timestamps are supported") ); parsers.add(new ParameterizedTokenParser("\\%\\{end:([^\\}]*%[^\\}]*)\\}t", "request.receive.time.end", "TIME.STRFTIME_", STRING_ONLY, FORMAT_STRING, 0, new StrfTimeStampDissector()) .setWarningMessageWhenUsed("Only some parts of localized timestamps are supported") ); // In addition to the formats supported by strftime(3), the following format tokens are supported: // sec number of seconds since the Epoch // msec number of milliseconds since the Epoch // usec number of microseconds since the Epoch // msec_frac millisecond fraction // usec_frac microsecond fraction // These tokens can not be combined with each other or strftime(3) formatting in the same format string. // You can use multiple %{format}t tokens instead. // sec parsers.addAll(createFirstAndLastTokenParsers("%{sec}t", "request.receive.time.sec", "TIME.SECONDS", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{begin:sec}t", "request.receive.time.begin.sec", "TIME.SECONDS", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{end:sec}t", "request.receive.time.end.sec", "TIME.SECONDS", STRING_OR_LONG, FORMAT_NUMBER)); // msec parsers.addAll(createFirstAndLastTokenParsers("%{msec}t", "request.receive.time.msec", "TIME.EPOCH", STRING_OR_LONG, FORMAT_NUMBER)); // Additional support for the deprecated old output addExtraOutput(parsers, "%{msec}t", new TokenOutputField("TIME.EPOCH", "request.receive.time.begin.msec", STRING_OR_LONG) .deprecateFor("TIME.EPOCH:request.receive.time.msec")); parsers.addAll(createFirstAndLastTokenParsers("%{begin:msec}t", "request.receive.time.begin.msec", "TIME.EPOCH", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{end:msec}t", "request.receive.time.end.msec", "TIME.EPOCH", STRING_OR_LONG, FORMAT_NUMBER)); // usec parsers.addAll(createFirstAndLastTokenParsers("%{usec}t", "request.receive.time.usec", "TIME.EPOCH.USEC", STRING_OR_LONG, FORMAT_NUMBER)); // Additional support for the deprecated old output addExtraOutput(parsers, "%{usec}t", new TokenOutputField("TIME.EPOCH.USEC", "request.receive.time.begin.usec", STRING_OR_LONG) .deprecateFor("TIME.EPOCH.USEC:request.receive.time.usec")); parsers.addAll(createFirstAndLastTokenParsers("%{begin:usec}t", "request.receive.time.begin.usec", "TIME.EPOCH.USEC", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{end:usec}t", "request.receive.time.end.usec", "TIME.EPOCH.USEC", STRING_OR_LONG, FORMAT_NUMBER)); // msec_frac parsers.addAll(createFirstAndLastTokenParsers("%{msec_frac}t", "request.receive.time.msec_frac", "TIME.EPOCH", STRING_OR_LONG, FORMAT_NUMBER)); addExtraOutput(parsers, "%{msec_frac}t", new TokenOutputField("TIME.EPOCH", "request.receive.time.begin.msec_frac", STRING_OR_LONG) .deprecateFor("TIME.EPOCH:request.receive.time.msec_frac")); parsers.addAll(createFirstAndLastTokenParsers("%{begin:msec_frac}t", "request.receive.time.begin.msec_frac", "TIME.EPOCH", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{end:msec_frac}t", "request.receive.time.end.msec_frac", "TIME.EPOCH", STRING_OR_LONG, FORMAT_NUMBER)); // usec_frac parsers.addAll(createFirstAndLastTokenParsers("%{usec_frac}t", "request.receive.time.usec_frac", "TIME.EPOCH.USEC_FRAC", STRING_OR_LONG, FORMAT_NUMBER)); // Additional support for the deprecated old output addExtraOutput(parsers, "%{usec_frac}t", new TokenOutputField("TIME.EPOCH.USEC_FRAC", "request.receive.time.begin.usec_frac", STRING_OR_LONG) .deprecateFor("TIME.EPOCH.USEC_FRAC:request.receive.time.usec_frac")); parsers.addAll(createFirstAndLastTokenParsers("%{begin:usec_frac}t", "request.receive.time.begin.usec_frac", "TIME.EPOCH.USEC_FRAC", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{end:usec_frac}t", "request.receive.time.end.usec_frac", "TIME.EPOCH.USEC_FRAC", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %T The time taken to serve the request, in seconds. parsers.addAll(createFirstAndLastTokenParsers("%T", "response.server.processing.time", "SECONDS", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %D The time taken to serve the request, in microseconds. parsers.addAll(createFirstAndLastTokenParsers("%D", "response.server.processing.time", "MICROSECONDS", STRING_OR_LONG, FORMAT_NUMBER)); // Additional support for the deprecated old output addExtraOutput(parsers, "%D", new TokenOutputField("MICROSECONDS", "server.process.time", STRING_OR_LONG) .deprecateFor("MICROSECONDS:response.server.processing.time")); // ------- // %{UNIT}T The time taken to serve the request, in a time unit given by UNIT. // Valid units are ms for milliseconds, us for microseconds, and s for seconds. // Using s gives the same result as %T without any format; // Using us gives the same result as %D. parsers.addAll(createFirstAndLastTokenParsers("%{us}T", "response.server.processing.time", "MICROSECONDS", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{ms}T", "response.server.processing.time", "MILLISECONDS", STRING_OR_LONG, FORMAT_NUMBER)); parsers.addAll(createFirstAndLastTokenParsers("%{s}T", "response.server.processing.time", "SECONDS", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // %u Remote user (from auth; may be bogus if return status (%s) is 401) parsers.addAll(createFirstAndLastTokenParsers("%u", "connection.client.user", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %U The URL path requested, not including any query string. parsers.addAll(createFirstAndLastTokenParsers("%U", "request.urlpath", "URI", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %v The canonical ServerName of the server serving the request. parsers.addAll(createFirstAndLastTokenParsers("%v", "connection.server.name.canonical", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %V The server name according to the UseCanonicalName setting. parsers.addAll(createFirstAndLastTokenParsers("%V", "connection.server.name", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %X Connection status when response is completed: // X = connection aborted before the response completed. // + = connection may be kept alive after the response is sent. // - = connection will be closed after the response is sent. // (This directive was %c in late versions of Apache 1.3, but this // conflicted with the historical ssl %{var}c syntax.) parsers.addAll(createFirstAndLastTokenParsers("%X", "response.connection.status", "HTTP.CONNECTSTATUS", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // %I Bytes received, including request and headers, cannot be zero. You // need to enable mod_logio to use this. // NOTE: In reality this CAN ben 0 (in case of HTTP 408 error code) parsers.addAll(createFirstAndLastTokenParsers("%I", "request.bytes", "BYTES", STRING_OR_LONG, FORMAT_CLF_NUMBER)); // ------- // %O Bytes sent, including headers, cannot be zero. You need to enable // mod_logio to use this. // NOTE: In reality this CAN ben 0 (in case of HTTP 408 error code) parsers.addAll(createFirstAndLastTokenParsers("%O", "response.bytes", "BYTES", STRING_OR_LONG, FORMAT_CLF_NUMBER)); // ------- // %S Bytes transferred (received and sent), including request and headers, cannot be zero. // This is the combination of %I and %O. You need to enable mod_logio to use this. parsers.addAll(createFirstAndLastTokenParsers("%S", "total.bytes", "BYTES", STRING_OR_LONG, TokenParser.FORMAT_NON_ZERO_NUMBER)); // Some explicit type overrides. // The '1' at the end indicates this is more important than the default TokenParser (which has an implicit 0). parsers.addAll(createFirstAndLastTokenParsers("%{cookie}i", "request.cookies", "HTTP.COOKIES", STRING_ONLY, FORMAT_STRING, 1)); parsers.addAll(createFirstAndLastTokenParsers("%{set-cookie}o", "response.cookies", "HTTP.SETCOOKIES", STRING_ONLY, FORMAT_STRING, 1)); parsers.addAll(createFirstAndLastTokenParsers("%{user-agent}i", "request.user-agent", "HTTP.USERAGENT", STRING_ONLY, FORMAT_STRING, 1)); parsers.addAll(createFirstAndLastTokenParsers("%{referer}i", "request.referer", "HTTP.URI", STRING_ONLY, FORMAT_STRING, 1)); return parsers; } private void addExtraOutput(List parsers, final String nLogFormatToken, TokenOutputField tokenOutputField) { for (TokenParser tokenParser:parsers) { if (tokenParser.getLogFormatToken().equals(nLogFormatToken)){ tokenParser.addOutputField(tokenOutputField); return; } } } private List createFirstAndLastTokenParsers( final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex) { return createFirstAndLastTokenParsers(nLogFormatToken, nValueName, nValueType, nCasts, nRegex, 0); } private List createFirstAndLastTokenParsers( final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex, final int nPrio) { List parsers = new ArrayList<>(3); // Quote from http://httpd.apache.org/docs/current/mod/mod_log_config.html#modifiers // The modifiers "<" and ">" can be used for requests that have been internally redirected to // choose whether the original or final (respectively) request should be consulted. // By default, the % directives %s, %U, %T, %D, and %r look at the original request // while all others look at the final request. // So for example, %>s can be used to record the final status of the request and %X' hence we output BOTH parsers.add(new TokenParser(nLogFormatToken, nRegex, nPrio) .addOutputField(nValueType, nValueName, nCasts) .addOutputField(nValueType, nValueName + ".last", nCasts) ); break; } parsers.add(new TokenParser(nLogFormatToken.replaceFirst("%", "%<"), nRegex, nPrio) .addOutputField(nValueType, nValueName + ".original", nCasts) ); parsers.add(new TokenParser(nLogFormatToken.replaceFirst("%", "%>"), nRegex, nPrio) .addOutputField(nValueType, nValueName + ".last", nCasts) ); return parsers; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/HttpdLogFormatDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenFormatDissector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import static nl.basjes.parse.core.Casts.NO_CASTS; public class HttpdLogFormatDissector extends Dissector { private static final Logger LOG = LoggerFactory.getLogger(HttpdLogFormatDissector.class); // This value MUST be the same for all formats this dissector can wrap public static final String INPUT_TYPE = "HTTPLOGLINE"; private final List registeredLogFormats; private final List dissectors; private TokenFormatDissector activeDissector; public HttpdLogFormatDissector() { registeredLogFormats = new ArrayList<>(16); dissectors = new ArrayList<>(16); activeDissector = null; } public HttpdLogFormatDissector(final String multiLineLogFormat) { this(); addMultipleLogFormats(multiLineLogFormat); if (enableJettyFix) { addAdditionalLogFormatsToHandleJettyUseragentProblem(); } } // Jetty has two (historical) problems: // 1) An empty user field was logged in the past as " - " instead of "-" // See: https://github.com/eclipse/jetty.project/commit/2332b4f // 2) An empty useragent field was logged with an extra trailing space. // This boolean enables a hack to parse these files. private boolean enableJettyFix = false; private void addAdditionalLogFormatsToHandleJettyUseragentProblem() { for (String logFormat : getAllLogFormats()) { if (logFormat.contains("\"%{User-Agent}i\"")) { LOG.info("Creating extra logformat to handle Jetty useragent problem."); String patchedLogFormat = logFormat.replace("\"%{User-Agent}i\"", "\"%{User-Agent}i\" "); addLogFormat(patchedLogFormat); } } // Jetty has suffered from this historical problem: // An empty user field was logged in the past as " - " instead of "-" // See: https://github.com/eclipse/jetty.project/commit/2332b4f for (String logFormat : getAllLogFormats()) { if (logFormat.contains("%u")) { LOG.info("Creating extra logformat to handle Jetty userfield problem."); String patchedLogFormat = logFormat.replace("%u", " %u "); addLogFormat(patchedLogFormat); } } } public HttpdLogFormatDissector enableJettyFix() { enableJettyFix = true; return this; } public HttpdLogFormatDissector addMultipleLogFormats(final String multiLineLogFormat) { return addLogFormat(Arrays.asList(multiLineLogFormat.split("\\r?\\n"))); } public HttpdLogFormatDissector addLogFormat(final List logFormats) { for (String logFormat : logFormats) { addLogFormat(logFormat); } return this; } public HttpdLogFormatDissector addLogFormat(final String logFormat) { if (logFormat == null || logFormat.trim().isEmpty()) { return this; // Skip this one } if (logFormat.toUpperCase().trim().equals("ENABLE JETTY FIX")) { return enableJettyFix(); } if (registeredLogFormats.contains(logFormat)) { LOG.info("Skipping duplicate LogFormat: >>{}<<", logFormat); return this; // We already have this one } registeredLogFormats.add(logFormat); switch (determineMostLikelyLogFormat(logFormat)) { case APACHE: LOG.info("Registering APACHE HTTPD LogFormat[{}]= >>{}<<", dissectors.size(), logFormat); dissectors.add(new ApacheHttpdLogFormatDissector(logFormat)); break; case NGINX: LOG.info("Registering NGINX LogFormat[{}]= >>{}<<", dissectors.size(), logFormat); dissectors.add(new NginxHttpdLogFormatDissector(logFormat)); break; default: LOG.error("Unable to determine if this is an APACHE or a NGINX LogFormat= >>{}<<", logFormat); break; } return this; } private enum LogFormatType { APACHE, NGINX, UNKNOWN } private LogFormatType determineMostLikelyLogFormat(final String logFormat) { if (ApacheHttpdLogFormatDissector.looksLikeApacheFormat(logFormat)) { return LogFormatType.APACHE; } if (NginxHttpdLogFormatDissector.looksLikeNginxFormat(logFormat)) { return LogFormatType.NGINX; } // We do not know return LogFormatType.UNKNOWN; } @Override public boolean initializeFromSettingsParameter(String multiLineLogFormat) { addMultipleLogFormats(multiLineLogFormat); return true; } @Override public void createAdditionalDissectors(Parser parser) { for (Dissector dissector : dissectors) { dissector.createAdditionalDissectors(parser); } } @Override public void dissect(Parsable parsable, String inputname) throws DissectionFailure { if (dissectors.isEmpty()) { throw new DissectionFailure("We need one or more logformats before we can dissect."); } // Initial: We must determine the right dissector if (activeDissector == null) { activeDissector = dissectors.get(0); LOG.info("At start we use LogFormat[0]= >>{}<<", activeDissector.getLogFormat()); } try { activeDissector.dissect(parsable, inputname); } catch (DissectionFailure df) { if (dissectors.size() > 1) { int index = 0; for (TokenFormatDissector dissector : dissectors) { try { dissector.dissect(parsable, inputname); LOG.info("Switched to LogFormat[{}]= >>{}<<", index, activeDissector.getLogFormat()); activeDissector = dissector; return; } catch (DissectionFailure e) { index++; // We ignore the error and try the next one. } } } throw df; } } @Override public String getInputType() { return INPUT_TYPE; } @Override public List getPossibleOutput() { if (dissectors.isEmpty()) { return Collections.emptyList(); } Set result = new HashSet<>(32); // Go via a Set to deduplicate the fields for (Dissector dissector : dissectors) { result.addAll(dissector.getPossibleOutput()); } return new ArrayList<>(result); } @Override public EnumSet prepareForDissect(String inputname, String outputname) { if (dissectors.isEmpty()) { return NO_CASTS; } EnumSet result = EnumSet.noneOf(Casts.class); // Start empty for (Dissector dissector : dissectors) { result.addAll(dissector.prepareForDissect(inputname, outputname)); } return result; } @Override public void prepareForRun() throws InvalidDissectorException { if (dissectors.isEmpty()) { throw new InvalidDissectorException("Cannot run without logformats"); } for (Dissector dissector : dissectors) { if (!INPUT_TYPE.equals(dissector.getInputType())) { throw new InvalidDissectorException("All dissectors controlled by " + this.getClass().getCanonicalName() + " MUST have \"" + INPUT_TYPE + "\" as their inputtype."); } dissector.prepareForRun(); } } private List getAllLogFormats() { List result = new ArrayList<>(dissectors.size()); for (Dissector dissector : dissectors) { if (dissector instanceof TokenFormatDissector) { result.add(((TokenFormatDissector) dissector).getLogFormat()); } } return result; } @Override protected void initializeNewInstance(Dissector newInstance) { if (dissectors.isEmpty()) { return; } if (newInstance instanceof HttpdLogFormatDissector) { ((HttpdLogFormatDissector) newInstance).addLogFormat(getAllLogFormats()); if (enableJettyFix) { ((HttpdLogFormatDissector) newInstance).enableJettyFix(); } } else { LOG.error("============================== WTF == {}", newInstance.getClass().getCanonicalName()); } } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/HttpdLoglineParser.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Parser; import nl.basjes.parse.httpdlog.dissectors.HttpFirstLineDissector; import nl.basjes.parse.httpdlog.dissectors.HttpFirstLineProtocolDissector; import nl.basjes.parse.httpdlog.dissectors.HttpUriDissector; import nl.basjes.parse.httpdlog.dissectors.ModUniqueIdDissector; import nl.basjes.parse.httpdlog.dissectors.QueryStringFieldDissector; import nl.basjes.parse.httpdlog.dissectors.RequestCookieListDissector; import nl.basjes.parse.httpdlog.dissectors.ResponseSetCookieDissector; import nl.basjes.parse.httpdlog.dissectors.ResponseSetCookieListDissector; import nl.basjes.parse.httpdlog.dissectors.TimeStampDissector; import nl.basjes.parse.httpdlog.dissectors.translate.ConvertCLFIntoNumber; import nl.basjes.parse.httpdlog.dissectors.translate.ConvertNumberIntoCLF; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HttpdLoglineParser extends Parser { private static final Logger LOG = LoggerFactory.getLogger(HttpdLoglineParser.class); // -------------------------------------------- public HttpdLoglineParser( final Class clazz, final String logformat) { super(clazz); logVersion(); setupDissectors(logformat, null); } // -------------------------------------------- public static void logVersion(){ String[] lines = { "Apache HTTPD & NGINX Access log parsing made easy", "For more information: https://github.com/nielsbasjes/logparser", "Copyright (C) 2011-2023 Niels Basjes - License Apache 2.0" }; String version = getVersion(); int width = version.length(); for (String line: lines) { width = Math.max(width, line.length()); } LOG.info(""); LOG.info("/-{}-\\", padding('-', width)); logLine(version, width); LOG.info("+-{}-+", padding('-', width)); for (String line: lines) { logLine(line, width); } LOG.info("\\-{}-/", padding('-', width)); LOG.info(""); } private static String padding(char letter, int count) { StringBuilder sb = new StringBuilder(128); for (int i=0; i clazz, final String logformat, final String timestampFormat) { super(clazz); setupDissectors(logformat, timestampFormat); } private void setupDissectors( final String logformat, final String timestampFormat) { // The pieces we have to get there addDissector(new HttpdLogFormatDissector(logformat)); addDissector(new TimeStampDissector("TIME.STAMP", timestampFormat)); addDissector(new TimeStampDissector("TIME.ISO8601", "yyyy-MM-dd'T'HH:mm:ssXXX")); addDissector(new HttpFirstLineDissector()); addDissector(new HttpFirstLineProtocolDissector()); addDissector(new HttpUriDissector()); addDissector(new QueryStringFieldDissector()); addDissector(new RequestCookieListDissector()); addDissector(new ResponseSetCookieListDissector()); addDissector(new ResponseSetCookieDissector()); addDissector(new ModUniqueIdDissector()); // Type translators addDissector(new ConvertCLFIntoNumber("BYTESCLF", "BYTES")); addDissector(new ConvertNumberIntoCLF("BYTES", "BYTESCLF")); // And we define the input for this parser setRootType(HttpdLogFormatDissector.INPUT_TYPE); } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/NginxHttpdLogFormatDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.SimpleDissector; import nl.basjes.parse.core.Value; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.httpdlog.dissectors.nginxmodules.CoreLogModule; import nl.basjes.parse.httpdlog.dissectors.nginxmodules.GeoIPModule; import nl.basjes.parse.httpdlog.dissectors.nginxmodules.KubernetesIngressModule; import nl.basjes.parse.httpdlog.dissectors.nginxmodules.NginxModule; import nl.basjes.parse.httpdlog.dissectors.nginxmodules.SslModule; import nl.basjes.parse.httpdlog.dissectors.nginxmodules.UpstreamModule; import nl.basjes.parse.httpdlog.dissectors.nginxmodules.VariousModule; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenFormatDissector; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import nl.basjes.parse.httpdlog.dissectors.translate.ConvertMillisecondsIntoMicroseconds; import nl.basjes.parse.httpdlog.dissectors.translate.ConvertSecondsWithMillisStringDissector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; @SuppressWarnings({ "PMD.LongVariable", // I like my variable names this way "PMD.CyclomaticComplexity", "PMD.OnlyOneReturn", "PMD.BeanMembersShouldSerialize", // No beans here "PMD.DataflowAnomalyAnalysis" // Results in a lot of mostly useless messages. }) public class NginxHttpdLogFormatDissector extends TokenFormatDissector { private static final Logger LOG = LoggerFactory.getLogger(NginxHttpdLogFormatDissector.class); public NginxHttpdLogFormatDissector(final String logFormat) { super(logFormat); setInputType(HttpdLogFormatDissector.INPUT_TYPE); } public NginxHttpdLogFormatDissector() { super(); setInputType(HttpdLogFormatDissector.INPUT_TYPE); } private void overrideLogFormat(String originalLogformat, String logformat) { LOG.debug("Specified logformat \"{}\" was mapped to {}", originalLogformat, logformat); super.setLogFormat(logformat); } @Override public void setLogFormat(final String logformat) { // https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format // The configuration always includes the predefined “combined” format: // log_format combined '$remote_addr - $remote_user [$time_local] ' // '"$request" $status $body_bytes_sent ' // '"$http_referer" "$http_user_agent"'; switch (logformat.toLowerCase(Locale.getDefault())) { case "combined": overrideLogFormat(logformat, "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""); break; default: super.setLogFormat(logformat); break; } } public static boolean looksLikeNginxFormat(String logFormat) { if (logFormat.indexOf('$') != -1) { return true; } switch (logFormat.toLowerCase(Locale.getDefault())) { case "combined": return true; default: return false; } } // -------------------------------------------- @Override public String decodeExtractedValue(String tokenName, String value) { if (value == null || value.equals("")) { return value; } // In Apache logfiles a '-' means a 'not specified' / 'empty' value. if (value.equals("-")) { return null; } return value; } private static final List MODULES = new ArrayList<>(); static { MODULES.add(new CoreLogModule()); MODULES.add(new UpstreamModule()); MODULES.add(new SslModule()); MODULES.add(new GeoIPModule()); MODULES.add(new VariousModule()); MODULES.add(new KubernetesIngressModule()); } // -------------------------------------------- @Override protected List createAllTokenParsers() { List parsers = new ArrayList<>(); MODULES.forEach(m -> parsers.addAll(m.getTokenParsers())); return parsers; } @Override public void createAdditionalDissectors(Parser parser) { super.createAdditionalDissectors(parser); parser.addDissector(new BinaryIPDissector()); parser.addDissector(new ConvertSecondsWithMillisStringDissector("SECOND_MILLIS", "MILLISECONDS")); parser.addDissector(new ConvertSecondsWithMillisStringDissector("TIME.EPOCH_SECOND_MILLIS", "TIME.EPOCH")); parser.addDissector(new ConvertMillisecondsIntoMicroseconds("MILLISECONDS", "MICROSECONDS")); MODULES.forEach(m -> parser.addDissectors(m.getDissectors())); } public static class BinaryIPDissector extends SimpleDissector { private static final HashMap> EPOCH_MILLIS_CONFIG = new HashMap<>(); static { EPOCH_MILLIS_CONFIG.put("IP:", STRING_OR_LONG); } public BinaryIPDissector() { super("IP_BINARY", EPOCH_MILLIS_CONFIG); } private static final String CAPTURE_HEX_BYTE = "\\\\x([0-9a-fA-F][0-9a-fA-F])"; final Pattern binaryIPPattern = Pattern.compile( CAPTURE_HEX_BYTE+CAPTURE_HEX_BYTE+CAPTURE_HEX_BYTE+CAPTURE_HEX_BYTE ); @Override public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure { Matcher matcher = binaryIPPattern.matcher(value.getString()); if (matcher.matches()) { String ip = String.valueOf(Utils.hexCharsToByte(matcher.group(1))) + '.' + String.valueOf(Utils.hexCharsToByte(matcher.group(2))) + '.' + String.valueOf(Utils.hexCharsToByte(matcher.group(3))) + '.' + String.valueOf(Utils.hexCharsToByte(matcher.group(4))); parsable.addDissection(inputname, "IP", "", ip); } } } // This is marked as deprecated because we want to mark all uses of this as "undesirable" @Deprecated public static class NotYetImplemented extends NotImplementedTokenParser { private static final String FIELD_PREFIX = "nginx_parameter"; public NotYetImplemented(final String nLogFormatToken) { super(nLogFormatToken, FIELD_PREFIX, 0); } public NotYetImplemented(final String nLogFormatToken, final String regex) { super(nLogFormatToken, FIELD_PREFIX, regex, 0); } public NotYetImplemented(final String nLogFormatToken, final String regex, final int prio) { super(nLogFormatToken, FIELD_PREFIX, regex, prio); } public NotYetImplemented(final String nLogFormatToken, final int prio) { super(nLogFormatToken, FIELD_PREFIX, "[^\" ]*", prio); } } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/Utils.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import org.apache.commons.text.StringEscapeUtils; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; public final class Utils { private Utils() {} private static final Pattern CHOPPED_STANDARD = Pattern.compile("%[0-9A-Fa-f]?$"); private static final Pattern VALID_NON_STANDARD = Pattern.compile("%u([0-9A-Fa-f][0-9A-Fa-f])+"); private static final Pattern CHOPPED_NON_STANDARD = Pattern.compile("%u[0-9A-Fa-f]{0,3}$"); /** * The main goal of the resilientUrlDecode is to have a UrlDecode that keeps working * even if the input is seriously flawed or even uses a rejected standard. * @param input the UrlEncoded input string * @return Url decoded result string */ public static String resilientUrlDecode(String input) { String cookedInput = input; if (cookedInput.indexOf('%') > -1) { // Discard chopped encoded char at the end of the line (there is no way to know what it was) cookedInput = CHOPPED_STANDARD.matcher(cookedInput).replaceAll(""); // Handle non standard (rejected by W3C) encoding that is used anyway by some // See: https://stackoverflow.com/a/5408655/114196 if (cookedInput.contains("%u")) { cookedInput = replaceString(cookedInput, "%u00", "%u"); // Transform all existing non standard into UTF-8 standard. cookedInput = VALID_NON_STANDARD.matcher(cookedInput).replaceAll("%$1"); // Discard chopped encoded char at the end of the line cookedInput = CHOPPED_NON_STANDARD.matcher(cookedInput).replaceAll(""); } } try { return URLDecoder.decode(cookedInput, "UTF-8"); } catch (UnsupportedEncodingException e) { // Will never happen because the encoding is hardcoded return null; } } public static byte hexCharsToByte(String twoHexDigits) { if (twoHexDigits == null || twoHexDigits.length() != 2) { throw new IllegalArgumentException("URLDecoder: Illegal hex characters : \"" + twoHexDigits + "\""); } return hexCharsToByte(twoHexDigits.charAt(0), twoHexDigits.charAt(1)); } public static byte hexCharsToByte(char c1, char c2){ byte result; switch (c1) { case '0': result = (byte)0x00; break; case '1': result = (byte)0x10; break; case '2': result = (byte)0x20; break; case '3': result = (byte)0x30; break; case '4': result = (byte)0x40; break; case '5': result = (byte)0x50; break; case '6': result = (byte)0x60; break; case '7': result = (byte)0x70; break; case '8': result = (byte)0x80; break; case '9': result = (byte)0x90; break; case 'a': result = (byte)0xa0; break; case 'b': result = (byte)0xb0; break; case 'c': result = (byte)0xc0; break; case 'd': result = (byte)0xd0; break; case 'e': result = (byte)0xe0; break; case 'f': result = (byte)0xf0; break; case 'A': result = (byte)0xa0; break; case 'B': result = (byte)0xb0; break; case 'C': result = (byte)0xc0; break; case 'D': result = (byte)0xd0; break; case 'E': result = (byte)0xe0; break; case 'F': result = (byte)0xf0; break; default: throw new IllegalArgumentException("URLDecoder: Illegal hex characters (char 1): '" + c1 + "'"); } switch (c2) { case '0': break; // result |= (byte)0x00; --> An OR with only 0 bits is useless case '1': result |= (byte)0x01; break; case '2': result |= (byte)0x02; break; case '3': result |= (byte)0x03; break; case '4': result |= (byte)0x04; break; case '5': result |= (byte)0x05; break; case '6': result |= (byte)0x06; break; case '7': result |= (byte)0x07; break; case '8': result |= (byte)0x08; break; case '9': result |= (byte)0x09; break; case 'a': result |= (byte)0x0a; break; case 'b': result |= (byte)0x0b; break; case 'c': result |= (byte)0x0c; break; case 'd': result |= (byte)0x0d; break; case 'e': result |= (byte)0x0e; break; case 'f': result |= (byte)0x0f; break; case 'A': result |= (byte)0x0a; break; case 'B': result |= (byte)0x0b; break; case 'C': result |= (byte)0x0c; break; case 'D': result |= (byte)0x0d; break; case 'E': result |= (byte)0x0e; break; case 'F': result |= (byte)0x0f; break; default: throw new IllegalArgumentException("URLDecoder: Illegal hex characters (char 2): '" + c2 + "'"); } return result; } /** * Decoder for this specification: * * http://httpd.apache.org/docs/current/mod/mod_log_config.html#formats * Format Notes * For security reasons, starting with version 2.0.46, non-printable and other special characters * in %r, %i and %o are escaped using \xhh sequences, where hh stands for the hexadecimal representation of * the raw byte. Exceptions from this rule are " and \, which are escaped by prepending a backslash, and * all whitespace characters, which are written in their C-style notation (\n, \t, etc). * * Actual method in the original code: ap_escape_logitem * https://github.com/apache/httpd/blob/trunk/server/util.c#L2001 * * @param input The value as it was logged by the Apache HTTPD. * @return The 'decoded' version of the logged value. */ public static String decodeApacheHTTPDLogValue(String input){ if (input == null || input.length() == 0) { return input; } if (!input.contains("\\")) { return input; } StringBuilder sb = new StringBuilder(input.length()); // https://stackoverflow.com/q/8894258/114196 : Fastest way to iterate over all the chars in a String for (int i = 0; i < input.length(); i++) { char chr = input.charAt(i); if (chr == '\\') { chr = input.charAt(++i); switch (chr){ case '"': case '\\': sb.append(chr); break; case 'b': sb.append('\b'); break; case 'n': sb.append('\n'); break; case 'r': sb.append('\r'); break; case 't': sb.append('\t'); break; case 'v': sb.append((char)hexCharsToByte('0', 'b')); break; case 'x': // This should be \xhh (hh = [0-9a-f][0-9a-f]) char chr1 = input.charAt(++i); char chr2 = input.charAt(++i); sb.append((char)hexCharsToByte(chr1, chr2)); break; default: // This shouldn't happen. // Let's just append the unmodified input for now. sb.append('\\').append(chr); } } else { sb.append(chr); } } return sb.toString(); } private static final Map HTML_ENTITY_REPLACE_MAP; private static String htmlEntityToURLEncoded(String entity) { try { return URLEncoder.encode(StringEscapeUtils.unescapeHtml4(entity), StandardCharsets.UTF_8.toString()); } catch (UnsupportedEncodingException e) { // This will never happen } return null; } static { // The list of common entities I chose to support on their name. List entities = Arrays.asList( " ", "<", ">", "&", """, "˜", "¢", "£", "¥", "€", "©", "®" ); Map aMap = new HashMap<>(); entities.forEach(entity -> aMap.put(entity, htmlEntityToURLEncoded(entity))); HTML_ENTITY_REPLACE_MAP = Collections.unmodifiableMap(aMap); } /** * Sometimes people put HTML encoded chars into a URL. * Because it is very hard to correctly decode these we are just making them 'inert' * so they do not break the rest of the processing. * @param uriString The input URI * @return Cleaned string */ public static String makeHTMLEncodedInert(String uriString) { String result = uriString; // For some entities we have a valid replace value. for (Map.Entry entry: HTML_ENTITY_REPLACE_MAP.entrySet()) { result = replaceString(result, entry.getKey(), entry.getValue()); } // For the rest we simply make it inert // TODO: Convert the codepoint to valid UTF-8 // Named entities ( like > and € ) result = result.replaceAll("&([a-zA-Z]+;)", "*$1"); // Numerical decimal entities result = result.replaceAll("&(#[0-9a-fA-F]+;)", "*$1"); // Numerical hexadecimal entities result = result.replaceAll("&(#x[0-9a-fA-F]+;)", "*$1"); return result; } // Copied from Yauaa public static String replaceString( final String input, final String searchFor, final String replaceWith ){ //startIdx and idxSearchFor delimit various chunks of input; these //chunks always end where searchFor begins int startIdx = 0; int idxSearchFor = input.indexOf(searchFor, startIdx); if (idxSearchFor < 0) { return input; } final StringBuilder result = new StringBuilder(input.length()+32); while (idxSearchFor >= 0) { //grab a part of input which does not include searchFor result.append(input, startIdx, idxSearchFor); //add replaceWith to take place of searchFor result.append(replaceWith); //reset the startIdx to just after the current match, to see //if there are any further matches startIdx = idxSearchFor + searchFor.length(); idxSearchFor = input.indexOf(searchFor, startIdx); } //the final chunk will go to the end of input result.append(input.substring(startIdx)); return result.toString(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/HttpFirstLineDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import static nl.basjes.parse.core.Casts.STRING_ONLY; public class HttpFirstLineDissector extends Dissector { // -------------------------------------------- // The "first line" of a request can be split up a bit further // See for more details: http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html // In https://tools.ietf.org/html/rfc7230#section-3.1.1 it says: // Recipients typically parse the request-line into its component parts // by splitting on whitespace (see Section 3.5), since no whitespace is // allowed in the three components. Unfortunately, some user agents // fail to properly encode or exclude whitespace found in hypertext // references, resulting in those disallowed characters being sent in a // request-target. // So this means: // - Method = Single Word // - Request URI = String that can contain ANY letters // - HTTP version = HTTP/[0-9]+\.[0-9]+ // The HTTP version has been made optional to allow parsing the log lines you get when the URI is > 8KB // In that scenario the HTTP/x.x part will not be logged at all. // In case of using mod_reqtimeout simply opening a connection and wait for the timeout without entering any data // results in an empty firstline. I.e. a "-" // The actual regex has been reduced to '.*' because we want to continue even if someone throws in complete garbage. public static final String FIRSTLINE_REGEX = ".*"; private final Pattern firstlineSplitter = Pattern .compile("^([a-zA-Z-_]+) (.*) (HTTP/[0-9]+\\.[0-9]+)$"); private final Pattern tooLongFirstlineSplitter = Pattern .compile("^([a-zA-Z-_]+) (.*)$"); // -------------------------------------------- private static final String HTTP_FIRSTLINE = "HTTP.FIRSTLINE"; @Override public String getInputType() { return HTTP_FIRSTLINE; } // -------------------------------------------- @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("HTTP.METHOD:method"); result.add("HTTP.URI:uri"); result.add("HTTP.PROTOCOL_VERSION:protocol"); return result; } // -------------------------------------------- @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(HTTP_FIRSTLINE, inputname); final String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty() || "-".equals(fieldValue)){ return; // Nothing to do here } // Now we create a matcher for this line Matcher matcher = firstlineSplitter.matcher(fieldValue); // Is it all as expected? boolean matches = matcher.find(); if (matches && matcher.groupCount() == 3) { outputDissection(parsable, inputname, "HTTP.METHOD", "method", matcher, 1); outputDissection(parsable, inputname, "HTTP.URI", "uri", matcher, 2); outputDissection(parsable, inputname, "HTTP.PROTOCOL_VERSION", "protocol", matcher, 3); return; } // In the scenario that the actual URI is too long the last part ("HTTP/1.1") may have been cut off by the // Apache HTTPD webserver. To still be able to parse these we try that pattern too // Now we create a matcher for this line matcher = tooLongFirstlineSplitter.matcher(fieldValue); // Is it all as expected? matches = matcher.find(); if (matches && matcher.groupCount() == 2) { outputDissection(parsable, inputname, "HTTP.METHOD", "method", matcher, 1); outputDissection(parsable, inputname, "HTTP.URI", "uri", matcher, 2); parsable.addDissection(inputname, "HTTP.PROTOCOL_VERSION", "protocol", (String) null); } } private void outputDissection(Parsable parsable, String inputname, String type, String name, Matcher matcher, int offset) throws DissectionFailure { if (requestedParameters.contains(name)) { parsable.addDissection(inputname, type, name, matcher.group(offset)); } } // -------------------------------------------- private final Set requestedParameters = new HashSet<>(16); @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { requestedParameters.add(extractFieldName(inputname, outputname)); return STRING_ONLY; } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/HttpFirstLineProtocolDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import static nl.basjes.parse.core.Casts.STRING_ONLY; public class HttpFirstLineProtocolDissector extends Dissector { // -------------------------------------------- private static final String INPUT_TYPE = "HTTP.PROTOCOL_VERSION"; @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("HTTP.PROTOCOL:"); result.add("HTTP.PROTOCOL.VERSION:version"); return result; } // -------------------------------------------- @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); final String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty() || "-".equals(fieldValue)){ return; // Nothing to do here } String[] protocol = fieldValue.split("/", 2); if (protocol.length == 2) { outputDissection(parsable, inputname, "HTTP.PROTOCOL", "", protocol[0]); outputDissection(parsable, inputname, "HTTP.PROTOCOL.VERSION", "version", protocol[1]); return; } // In the scenario that the actual URI is too long the last part ("HTTP/1.1") may have been cut off by the // Apache HTTPD webserver. To still be able to parse these we try that pattern too parsable.addDissection(inputname, "HTTP.PROTOCOL", "", (String) null); parsable.addDissection(inputname, "HTTP.PROTOCOL.VERSION", "version", (String) null); } private void outputDissection(Parsable parsable, String inputname, String type, String name, String value) throws DissectionFailure { if (requestedParameters.contains(name)) { parsable.addDissection(inputname, type, name, value); } } // -------------------------------------------- private final Set requestedParameters = new HashSet<>(16); @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { requestedParameters.add(extractFieldName(inputname, outputname)); return STRING_ONLY; } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/HttpUriDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import org.apache.commons.codec.net.URLCodec; import org.apache.commons.text.StringEscapeUtils; import java.net.URI; import java.util.ArrayList; import java.util.BitSet; import java.util.EnumSet; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import static java.nio.charset.StandardCharsets.US_ASCII; import static java.nio.charset.StandardCharsets.UTF_8; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; import static nl.basjes.parse.httpdlog.Utils.makeHTMLEncodedInert; public class HttpUriDissector extends Dissector { // -------------------------------------------- private static final String INPUT_TYPE = "HTTP.URI"; @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("HTTP.PROTOCOL:protocol"); result.add("HTTP.USERINFO:userinfo"); result.add("HTTP.HOST:host"); result.add("HTTP.PORT:port"); result.add("HTTP.PATH:path"); result.add("HTTP.QUERYSTRING:query"); result.add("HTTP.REF:ref"); return result; } // -------------------------------------------- private boolean wantProtocol = false; private boolean wantUserinfo = false; private boolean wantHost = false; private boolean wantPort = false; private boolean wantPath = false; private boolean wantQuery = false; private boolean wantRef = false; @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { String name = extractFieldName(inputname, outputname); if ("protocol".equals(name)) { wantProtocol = true; return STRING_ONLY; } if ("userinfo".equals(name)) { wantUserinfo = true; return STRING_ONLY; } if ("host".equals(name)) { wantHost = true; return STRING_ONLY; } if ("port".equals(name)) { wantPort = true; return STRING_OR_LONG; } if ("path".equals(name)) { wantPath = true; return STRING_ONLY; } if ("query".equals(name)) { wantQuery = true; return STRING_ONLY; } if ("ref".equals(name)) { wantRef = true; return STRING_ONLY; } return NO_CASTS; } // -------------------------------------------- // ---------------------------- Characters disallowed within the URI syntax // Excluded US-ASCII Characters are like control, space, delims and unwise private static final BitSet BAD_URI_CHARS = new BitSet(256); static { BAD_URI_CHARS.set(0, 255); // Unwise BAD_URI_CHARS.clear('{'); BAD_URI_CHARS.clear('}'); BAD_URI_CHARS.clear('|'); BAD_URI_CHARS.clear('\\'); BAD_URI_CHARS.clear('^'); BAD_URI_CHARS.clear('['); BAD_URI_CHARS.clear(']'); BAD_URI_CHARS.clear('`'); // Space BAD_URI_CHARS.clear(0x20); // Control BAD_URI_CHARS.clear(0, 0x1F); BAD_URI_CHARS.clear(0x7F); // Extra BAD_URI_CHARS.clear('<'); BAD_URI_CHARS.clear('>'); BAD_URI_CHARS.clear('"'); } // Match % encoded chars that are NOT followed by hex chars (may be at the end of the string) private static final Pattern BAD_EXCAPE_PATTERN = Pattern.compile("%([^0-9a-fA-F]|[0-9a-fA-F][^0-9a-fA-F]|.$|$)"); private static final Pattern EQUALS_HASH_PATTERN = Pattern.compile("=#"); private static final Pattern HASH_AMP_PATTERN = Pattern.compile("#&"); private static final Pattern DOUBLE_HASH_PATTERN = Pattern.compile("#(.*)#"); private static final Pattern ALMOST_HTML_ENCODED = Pattern.compile("([^&])(#x[0-9a-fA-F][0-9a-fA-F];)"); @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); String uriString = field.getValue().getString(); if (uriString == null || uriString.isEmpty()) { return; // Nothing to do here } // First we cleanup the URI so we fail less often over 'garbage' URIs. // See: https://stackoverflow.com/questions/11038967/brackets-in-a-request-url-are-legal-but-not-in-a-uri-java uriString = new String(URLCodec.encodeUrl(BAD_URI_CHARS, uriString.getBytes(UTF_8)), US_ASCII); // Now we translate any HTML encoded entities/characters into URL UTF-8 encoded characters uriString = makeHTMLEncodedInert(uriString); // Before we hand it to the standard parser we hack it around a bit so we can parse // nasty edge cases that are illegal yet do occur in real clickstreams. // Also we force the query string to start with ?& so the returned query string starts with & // Which leads to more consistent output after parsing. int firstQuestionMark = uriString.indexOf('?'); int firstAmpersand = uriString.indexOf('&'); // Now we can have one of 3 situations: // 1) No query string // 2) Query string starts with a '?' // (and optionally followed by one or more '&' or '?' ) // 3) Query string starts with a '&'. This is invalid but does occur! // We may have ?x=x&y=y?z=z so we normalize it always // to: ?&x=x&y=y&z=z if (firstAmpersand != -1 || firstQuestionMark != -1) { uriString = uriString.replace("?", "&"); uriString = uriString.replaceFirst("&", "?&"); } // We find that people muck up the URL by putting % signs in the URLs that are NOT escape sequences // So any % that is not followed by a two 'hex' letters is fixed uriString = BAD_EXCAPE_PATTERN.matcher(uriString).replaceAll("%25$1"); uriString = BAD_EXCAPE_PATTERN.matcher(uriString).replaceAll("%25$1"); // We have URIs with fragments like this: // /path/?_requestid=1234#x3D;12341234&Referrer=blablabla // So first we repair the broken encoded char uriString = ALMOST_HTML_ENCODED.matcher(uriString).replaceAll("$1&$2"); uriString = StringEscapeUtils.unescapeHtml4(uriString); // And we see URIs with this: // /path/?Referrer=ADV1234#&f=API&subid=#&name=12341234 uriString = EQUALS_HASH_PATTERN.matcher(uriString).replaceAll("="); uriString = HASH_AMP_PATTERN.matcher(uriString).replaceAll("&"); // If we still have multiple '#' in here we replace them with something else: '~' while (true) { Matcher doubleHashMatcher = DOUBLE_HASH_PATTERN.matcher(uriString); if (!doubleHashMatcher.find()) { break; } uriString = doubleHashMatcher.replaceAll("~$1#"); } boolean isUrl = true; URI uri; try { if (uriString.charAt(0) == '/') { uri = URI.create("dummy-protocol://dummy.host.name" + uriString); isUrl = false; // I.e. we do not return the values we just faked. } else { uri = URI.create(uriString); } } catch (IllegalArgumentException e) { // A bad parsing error happened so no dissection results. return; } if (wantQuery || wantPath || wantRef) { if (wantQuery) { String value = uri.getRawQuery(); if (value != null && !value.isEmpty()) { parsable.addDissection(inputname, "HTTP.QUERYSTRING", "query", value); } } if (wantPath) { String value = uri.getPath(); if (value != null && !value.isEmpty()) { parsable.addDissection(inputname, "HTTP.PATH", "path", value); } } if (wantRef) { String value = uri.getFragment(); if (value != null && !value.isEmpty()) { parsable.addDissection(inputname, "HTTP.REF", "ref", value); } } } if (isUrl) { if (wantProtocol) { String value = uri.getScheme(); if (value != null && !value.isEmpty()) { parsable.addDissection(inputname, "HTTP.PROTOCOL", "protocol", value); } } if (wantUserinfo) { String value = uri.getUserInfo(); if (value != null && !value.isEmpty()) { parsable.addDissection(inputname, "HTTP.USERINFO", "userinfo", value); } } if (wantHost) { String value = uri.getHost(); if (value != null && !value.isEmpty()) { parsable.addDissection(inputname, "HTTP.HOST", "host", value); } } if (wantPort) { int value = uri.getPort(); if (value != -1) { parsable.addDissection(inputname, "HTTP.PORT", "port", value); } } } } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/ModUniqueIdDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import org.apache.commons.codec.binary.Base64; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; /** * The documentation of mod_unique_id clearly states: * https://httpd.apache.org/docs/current/mod/mod_unique_id.html * ... it should be emphasized that applications should not dissect the encoding. ... * Applications should treat the entire encoded UNIQUE_ID as an opaque token, * which can be compared against other UNIQUE_IDs for equality only. * * Yet being able to peek inside is sometimes very useful... */ public class ModUniqueIdDissector extends Dissector { // -------------------------------------------- private static final String INPUT_TYPE = "MOD_UNIQUE_ID"; @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("TIME.EPOCH:epoch"); result.add("IP:ip"); result.add("PROCESSID:processid"); result.add("COUNTER:counter"); result.add("THREAD_INDEX:threadindex"); return result; } // -------------------------------------------- private boolean wantTime = false; private boolean wantIp = false; private boolean wantProcessId = false; private boolean wantCounter = false; private boolean wantThreadIndex = false; @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { String name = extractFieldName(inputname, outputname); if ("epoch".equals(name)) { wantTime = true; return STRING_OR_LONG; } if ("ip".equals(name)) { wantIp = true; return STRING_OR_LONG; } if ("processid".equals(name)) { wantProcessId = true; return STRING_OR_LONG; } if ("counter".equals(name)) { wantCounter = true; return STRING_OR_LONG; } if ("threadindex".equals(name)) { wantThreadIndex = true; return STRING_OR_LONG; } return NO_CASTS; } // -------------------------------------------- @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()) { return; // Nothing to do here } UniqueIdRec uniqueIdRec = decode(fieldValue); if (uniqueIdRec == null) { return; } if (wantTime) { parsable.addDissection(inputname, "TIME.EPOCH", "epoch", uniqueIdRec.timestamp); } if (wantIp) { parsable.addDissection(inputname, "IP", "ip", uniqueIdRec.ipaddrStr); } if (wantProcessId) { parsable.addDissection(inputname, "PROCESSID", "processid", uniqueIdRec.pid); } if (wantCounter) { parsable.addDissection(inputname, "COUNTER", "counter", uniqueIdRec.counter); } if (wantThreadIndex) { parsable.addDissection(inputname, "THREAD_INDEX", "threadindex", uniqueIdRec.threadIndex); } } // -------------------------------------------- private static final class UniqueIdRec { long timestamp; long ipaddr; String ipaddrStr; long pid; long counter; long threadIndex; } // 1 letter = 6 bits of data = 2^6 = 64 letters needed to do the mapping // 4 letters = 4*6 = 24 = 3*8 = 3 bytes // So 24 letters = 24*6 = 144 bits = 18 bytes public static final Charset CHARSET_UTF_8 = StandardCharsets.UTF_8; private static final byte[] EMPTY = {}; private byte[] decodeToBytes(String modUniqueIdString) { if (modUniqueIdString.length() != 24) { return EMPTY; } // http://httpd.apache.org/docs/current/mod/mod_unique_id.html // The UNIQUE_ID environment variable is constructed by encoding the 144-bit // (32-bit IP address, 32 bit pid, 32 bit time stamp, 16 bit counter, 32 bit thread index) // quadruple using the alphabet [A-Za-z0-9@-] in a manner similar to MIME base64 encoding, // producing 24 characters. // This implementation is based on the observation that the encoding used by mod-unique-id is // the same as Base64 except that the last two letters are different. // So by simply replacing the occurrences of these letters in the source we reuse and existing // Base64 decode implementation. byte[] modUniqueIdBytes = modUniqueIdString.getBytes(CHARSET_UTF_8); byte[] modUniqueIdBase64Bytes = new byte[modUniqueIdBytes.length]; for (int i = 0; i < modUniqueIdBytes.length; i++) { byte nextByte = modUniqueIdBytes[i]; switch (nextByte) { case '+': case '/': modUniqueIdBase64Bytes[i] = '@'; break; default: modUniqueIdBase64Bytes[i] = nextByte; break; } } try { return Base64.decodeBase64(modUniqueIdBase64Bytes); } catch (IllegalArgumentException iae) { return EMPTY; } } private UniqueIdRec decode(String modUniqueIdString) { byte[] bytes = decodeToBytes(modUniqueIdString); if (bytes == EMPTY) { return null; } // Is the decoded output the right length? if (bytes.length != 18) { return null; } UniqueIdRec result = new UniqueIdRec(); // http://httpd.apache.org/docs/current/mod/mod_unique_id.html // we will use a Unix timestamp (seconds since January 1, 1970 UTC) // (32-bit IP address, 32 bit pid, 32 bit time stamp, 16 bit counter, 32 bit thread index) // The actual ordering of the encoding is: time stamp, IP address, pid, counter. result.timestamp = (bytes[0] & 0xFF); result.timestamp = (result.timestamp * 256) + (bytes[1] & 0xFF); result.timestamp = (result.timestamp * 256) + (bytes[2] & 0xFF); result.timestamp = (result.timestamp * 256) + (bytes[3] & 0xFF); // Quote: The timestamp has only one second granularity result.timestamp *= 1000; // This is to convert the time into milliseconds // NOTE: In case of IPv6 the value will be related to the lower bits of the address. result.ipaddr = (bytes[4] & 0xFF); result.ipaddr = (result.ipaddr * 256) + (bytes[5] & 0xFF); result.ipaddr = (result.ipaddr * 256) + (bytes[6] & 0xFF); result.ipaddr = (result.ipaddr * 256) + (bytes[7] & 0xFF); result.ipaddrStr = "" + (bytes[4] & 0xFF) + '.' + (bytes[5] & 0xFF) + '.' + (bytes[6] & 0xFF) + '.' + (bytes[7] & 0xFF); result.pid = (bytes[8] & 0xFF); result.pid = (result.pid * 256) + (bytes[9] & 0xFF); result.pid = (result.pid * 256) + (bytes[10] & 0xFF); result.pid = (result.pid * 256) + (bytes[11] & 0xFF); result.counter = (bytes[12] & 0xFF); result.counter = (result.counter * 256) + (bytes[13] & 0xFF); result.threadIndex = (bytes[14] & 0xFF); result.threadIndex = (result.threadIndex * 256) + (bytes[15] & 0xFF); result.threadIndex = (result.threadIndex * 256) + (bytes[16] & 0xFF); result.threadIndex = (result.threadIndex * 256) + (bytes[17] & 0xFF); return result; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/QueryStringFieldDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.httpdlog.Utils.resilientUrlDecode; public class QueryStringFieldDissector extends Dissector { // -------------------------------------------- private static final String INPUT_TYPE = "HTTP.QUERYSTRING"; @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- /** This should output all possible types */ @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("STRING:*"); return result; } // -------------------------------------------- private final Set requestedParameters = new HashSet<>(16); @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { requestedParameters.add(extractFieldName(inputname, outputname)); return STRING_ONLY; } // -------------------------------------------- private boolean wantAllFields = false; @Override public void prepareForRun() { wantAllFields = requestedParameters.contains("*"); } // -------------------------------------------- @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()) { return; // Nothing to do here } String[] allValues = fieldValue.split("&"); for (String value : allValues) { int equalPos = value.indexOf('='); if (equalPos == -1) { if (!value.isEmpty()) { String name = value.toLowerCase(); if (wantAllFields || requestedParameters.contains(name)) { parsable.addDissection(inputname, "STRING", name, ""); } } } else { String name = value.substring(0, equalPos).toLowerCase(); if (wantAllFields || requestedParameters.contains(name)) { try { parsable.addDissection(inputname, "STRING", name, resilientUrlDecode(value.substring(equalPos + 1))); } catch (IllegalArgumentException e) { // This usually means that there was invalid encoding in the line throw new DissectionFailure(e.getMessage()); } } } } } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/RequestCookieListDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.httpdlog.Utils; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import static nl.basjes.parse.core.Casts.STRING_ONLY; public class RequestCookieListDissector extends Dissector { // -------------------------------------------- private static final String INPUT_TYPE = "HTTP.COOKIES"; @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- /** This should output all possible types */ @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("HTTP.COOKIE:*"); return result; } // -------------------------------------------- private final Set requestedCookies = new HashSet<>(16); @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { requestedCookies.add(extractFieldName(inputname, outputname)); return STRING_ONLY; } // -------------------------------------------- private boolean wantAllCookies = false; @Override public void prepareForRun() { wantAllCookies = requestedCookies.contains("*"); } // -------------------------------------------- // Cache the compiled pattern private final Pattern fieldSeparatorPattern = Pattern.compile("; "); @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); final String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()){ return; // Nothing to do here } String[] allValues = fieldSeparatorPattern.split(fieldValue); for (String value : allValues) { int equalPos = value.indexOf('='); if (equalPos == -1) { if (!"".equals(value)) { String theName = value.trim().toLowerCase(); // Just a name, no value if (wantAllCookies || requestedCookies.contains(theName)) { parsable.addDissection(inputname, "HTTP.COOKIE", theName, ""); } } } else { String theName = value.substring(0, equalPos).trim().toLowerCase(); if (wantAllCookies || requestedCookies.contains(theName)) { String theValue = value.substring(equalPos + 1).trim(); try { parsable.addDissection(inputname, "HTTP.COOKIE", theName, Utils.resilientUrlDecode(theValue)); } catch (IllegalArgumentException e) { // This usually means that there was invalid encoding in the line throw new DissectionFailure(e.getMessage()); } } } } } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/ResponseSetCookieDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; public class ResponseSetCookieDissector extends Dissector { // -------------------------------------------- private static final String INPUT_TYPE = "HTTP.SETCOOKIE"; @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- /** This should output all possible types */ @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("STRING:value"); result.add("STRING:expires"); result.add("TIME.EPOCH:expires"); result.add("STRING:path"); result.add("STRING:domain"); result.add("STRING:comment"); return result; } // -------------------------------------------- @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { String name = extractFieldName(inputname, outputname); switch (name) { case "expires": return STRING_OR_LONG; case "value": case "path": case "domain": case "comment": default: return STRING_ONLY; } } // -------------------------------------------- @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); final String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()){ return; // Nothing to do here } String[] parts = fieldValue.split(";"); for (int i = 0; i < parts.length; i++) { String part = parts[i].trim(); String[] keyValue = part.split("=", 2); String key = keyValue[0].trim(); String value = ""; if (keyValue.length == 2) { value = keyValue[1].trim(); } if (i==0) { parsable.addDissection(inputname, "STRING", "value", value); } else { switch (key) { // We ignore the max-age field because that is unsupported by IE anyway. case "expires": Long expires = parseExpire(value); // Backwards compatibility: STRING version is in seconds parsable.addDissection(inputname, "STRING", "expires", expires / 1000); parsable.addDissection(inputname, "TIME.EPOCH", "expires", expires); break; case "domain": parsable.addDissection(inputname, "STRING", "domain", value); break; case "comment": parsable.addDissection(inputname, "STRING", "comment", value); break; case "path": parsable.addDissection(inputname, "STRING", "path", value); break; default: // Ignore anything else } } } } // -------------------------------------------- private static final DateTimeFormatter[] DATE_FORMATS = { DateTimeFormatter.ofPattern("EEE',' dd-MMM-yyyy HH:mm:ss zzz").withZone(ZoneOffset.UTC), DateTimeFormatter.ofPattern("EEE',' dd MMM yyyy HH:mm:ss zzz").withZone(ZoneOffset.UTC), DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss 'GMT'Z") .withZone(ZoneOffset.UTC), }; private Long parseExpire(String expireString) { for (DateTimeFormatter dateFormat: DATE_FORMATS) { try { return dateFormat.parse(expireString, ZonedDateTime::from).toEpochSecond() * 1000; } catch (IllegalArgumentException iae) { // Ignore and continue } } return 0L; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/ResponseSetCookieListDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.net.HttpCookie; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; import static nl.basjes.parse.core.Casts.STRING_ONLY; public class ResponseSetCookieListDissector extends Dissector { // -------------------------------------------- private static final String INPUT_TYPE = "HTTP.SETCOOKIES"; @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- /** This should output all possible types */ @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("HTTP.SETCOOKIE:*"); return result; } // -------------------------------------------- private final Set requestedCookies = new HashSet<>(16); @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { requestedCookies.add(extractFieldName(inputname, outputname)); return STRING_ONLY; } // -------------------------------------------- private boolean wantAllCookies = false; @Override public void prepareForRun() { wantAllCookies = requestedCookies.contains("*"); } // -------------------------------------------- private final int minimalExpiresLength = "expires=XXXXXXX".length(); // Cache the compiled pattern private static final String SPLIT_BY = ", "; @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); final String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()){ return; // Nothing to do here } // This input is a ', ' separated list. // But the expires field can contain a ',' // and HttpCookie.parse(...) doesn't always work :( String[] parts = fieldValue.split(SPLIT_BY); String previous=""; for (String part:parts) { int expiresIndex = part.toLowerCase().indexOf("expires="); if (expiresIndex != -1) { if (part.length() - minimalExpiresLength < expiresIndex) { previous = part; continue; } } String value = part; if (!previous.isEmpty()) { value = previous+ SPLIT_BY +part; previous=""; } List cookies = HttpCookie.parse(value); for (HttpCookie cookie : cookies) { cookie.setVersion(1); String cookieName = cookie.getName().toLowerCase(); if (wantAllCookies || requestedCookies.contains(cookieName)) { parsable.addDissection(inputname, "HTTP.SETCOOKIE", cookieName, value); } } } } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/ScreenResolutionDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; public class ScreenResolutionDissector extends Dissector { public static final String SCREENRESOLUTION = "SCREENRESOLUTION"; private String separator = "x"; private boolean wantWidth = false; private boolean wantHeight = false; @Override public boolean initializeFromSettingsParameter(String settings) { if (settings.length() > 0) { this.separator = settings; } return true; } @Override public void dissect(Parsable parsable, String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(SCREENRESOLUTION, inputname); final String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()) { return; // Nothing to do here } if (fieldValue.contains(separator)) { String[] parts = fieldValue.split(separator); if (wantWidth) { parsable.addDissection(inputname, "SCREENWIDTH", "width", parts[0]); } if (wantHeight) { parsable.addDissection(inputname, "SCREENHEIGHT", "height", parts[1]); } } } @Override public String getInputType() { return SCREENRESOLUTION; } @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("SCREENWIDTH:width"); result.add("SCREENHEIGHT:height"); return result; } @Override public EnumSet prepareForDissect(String inputname, String outputname) { String name = extractFieldName(inputname, outputname); if ("width".equals(name)) { wantWidth = true; return STRING_OR_LONG; } if ("height".equals(name)) { wantHeight = true; return STRING_OR_LONG; } return NO_CASTS; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/StrfTimeStampDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; public class StrfTimeStampDissector extends Dissector { private final TimeStampDissector timeStampDissector; private String strfDateTimePattern = null; private String inputType = "TIME.?????"; public StrfTimeStampDissector() { timeStampDissector = new TimeStampDissector(); } public void setDateTimePattern(String newDateTimePattern) { if (newDateTimePattern == null) { timeStampDissector.setDateTimePattern(""); return; // Done } if (newDateTimePattern.equals(strfDateTimePattern)) { return; // Nothing to do } this.strfDateTimePattern = newDateTimePattern; timeStampDissector.setFormatter(StrfTimeToDateTimeFormatter.convert(newDateTimePattern)); } @Override public boolean initializeFromSettingsParameter(String settings) { setDateTimePattern(settings); return true; } @Override public void dissect(Parsable parsable, String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(inputType, inputname); timeStampDissector.dissect(field, parsable, inputname); } @Override public String getInputType() { return inputType; } @Override public List getPossibleOutput() { return timeStampDissector.getPossibleOutput(); } @Override public EnumSet prepareForDissect(String inputname, String outputname) { return timeStampDissector.prepareForDissect(inputname, outputname); } @Override public void prepareForRun() { timeStampDissector.prepareForRun(); } @Override protected void initializeNewInstance(Dissector newInstance) { StrfTimeStampDissector newStrfTimeStampDissector = (StrfTimeStampDissector) newInstance; newStrfTimeStampDissector.timeStampDissector.initializeNewInstance(newStrfTimeStampDissector.timeStampDissector); newStrfTimeStampDissector.setInputType(inputType); newStrfTimeStampDissector.setDateTimePattern(strfDateTimePattern); } @Override public void setInputType(String newInputType) { inputType = newInputType; } @Override public void createAdditionalDissectors(Parser parser) { parser.addDissector(new LocalizedTimeDissector(inputType)); } public static class LocalizedTimeDissector extends Dissector { String inputType = null; public LocalizedTimeDissector() { } public LocalizedTimeDissector(String inputType) { this.inputType = inputType; } @Override public void setInputType(String newInputType) { inputType = newInputType; } @Override public boolean initializeFromSettingsParameter(String settings) { setInputType(settings); return true; } @Override public void dissect(Parsable parsable, String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(inputType, inputname); parsable.addDissection(inputname, "TIME.LOCALIZEDSTRING", "", field.getValue()); } @Override public String getInputType() { return inputType; } @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("TIME.LOCALIZEDSTRING:"); return result; } @Override public EnumSet prepareForDissect(String inputname, String outputname) { return STRING_ONLY; } @Override protected void initializeNewInstance(Dissector newInstance) throws InvalidDissectorException { newInstance.setInputType(inputType); } } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/StrfTimeToDateTimeFormatter.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.strftime.StrfTimeBaseListener; import nl.basjes.parse.strftime.StrfTimeLexer; import nl.basjes.parse.strftime.StrfTimeParser; import org.antlr.v4.runtime.ANTLRErrorListener; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CodePointCharStream; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.RecognitionException; import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.atn.ATNConfigSet; import org.antlr.v4.runtime.dfa.DFA; import org.antlr.v4.runtime.tree.ParseTreeWalker; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.ZoneId; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.SignStyle; import java.time.format.TextStyle; import java.time.temporal.ChronoField; import java.time.temporal.WeekFields; import java.util.BitSet; import java.util.HashMap; import java.util.Locale; import java.util.Map; public final class StrfTimeToDateTimeFormatter extends StrfTimeBaseListener implements ANTLRErrorListener { private static final Logger LOG = LoggerFactory.getLogger(StrfTimeToDateTimeFormatter.class); private static final WeekFields LOCAL_WEEK_FIELDS = WeekFields.of(Locale.getDefault()); public static DateTimeFormatter convert(String strfformat) { return convert(strfformat, ZoneOffset.UTC); } public static DateTimeFormatter convert(String strfformat, ZoneId defaultZone) { CodePointCharStream input = CharStreams.fromString(strfformat); StrfTimeLexer lexer = new StrfTimeLexer(input); CommonTokenStream tokens = new CommonTokenStream(lexer); StrfTimeParser parser = new StrfTimeParser(tokens); lexer.removeErrorListeners(); parser.removeErrorListeners(); ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker StrfTimeToDateTimeFormatter converter = new StrfTimeToDateTimeFormatter(strfformat, defaultZone); lexer.addErrorListener(converter); parser.addErrorListener(converter); StrfTimeParser.PatternContext pattern = parser.pattern(); walker.walk(converter, pattern); // initiate walk of tree with listener if (converter.hasSyntaxError()) { return null; } return converter.build(); } private final String strfformat; private final DateTimeFormatterBuilder builder; private final ZoneId defaultZone; private boolean zoneWasSpecified = false; private StrfTimeToDateTimeFormatter(String inputStrfformat, ZoneId newDefaultZone) { strfformat = inputStrfformat; defaultZone = newDefaultZone; builder = new DateTimeFormatterBuilder() .parseCaseInsensitive(); } public DateTimeFormatter build() { DateTimeFormatter dateTimeFormatter = builder.toFormatter(); if (!zoneWasSpecified) { dateTimeFormatter = dateTimeFormatter.withZone(defaultZone); LOG.warn("The timestamp format \"{}\" does NOT contain a timezone so we assume \"{}\".", strfformat, defaultZone.getDisplayName(TextStyle.SHORT, Locale.ENGLISH)); } return dateTimeFormatter; } // ------------- Error handling -------------- private boolean syntaxError = false; public boolean hasSyntaxError() { return syntaxError; } @Override public void syntaxError(Recognizer recognizer, Object o, int i, int i1, String s, RecognitionException e) { syntaxError = true; } @Override public void reportAmbiguity(org.antlr.v4.runtime.Parser parser, DFA dfa, int i, int i1, boolean b, BitSet bitSet, ATNConfigSet atnConfigSet) { // Ignoring this Antlr4 event } @Override public void reportAttemptingFullContext(org.antlr.v4.runtime.Parser parser, DFA dfa, int i, int i1, BitSet bitSet, ATNConfigSet atnConfigSet) { // Ignoring this Antlr4 event } @Override public void reportContextSensitivity(org.antlr.v4.runtime.Parser parser, DFA dfa, int i, int i1, int i2, ATNConfigSet atnConfigSet) { // Ignoring this Antlr4 event } public static class UnsupportedStrfField extends RuntimeException { public UnsupportedStrfField(String s) { super("The field '" + s + "' cannot be converted towards a DateTimeFormatter field."); } } // ------------- Mapping -------------- @Override public void enterMsecFrac(StrfTimeParser.MsecFracContext ctx) { // Apache HTTPD specific: milliseconds fraction builder.appendValue(ChronoField.MILLI_OF_SECOND, 3); } @Override public void enterUsecFrac(StrfTimeParser.UsecFracContext ctx) { // Apache HTTPD specific: microseconds fraction builder.appendValue(ChronoField.MICRO_OF_SECOND, 6); } @Override public void enterText(StrfTimeParser.TextContext ctx) { builder.appendLiteral(ctx.getText()); } @Override public void enterTab(StrfTimeParser.TabContext ctx) { builder.appendLiteral('\t'); } @Override public void enterPercent(StrfTimeParser.PercentContext ctx) { builder.appendLiteral('%'); } @Override public void enterNewline(StrfTimeParser.NewlineContext ctx) { builder.appendLiteral('\n'); } @Override public void enterPa(StrfTimeParser.PaContext ctx) { // %a The abbreviated name of the day of the week according to the current locale. builder.appendText(ChronoField.DAY_OF_WEEK, TextStyle.SHORT); } @Override public void enterPA(StrfTimeParser.PAContext ctx) { // %A The full name of the day of the week according to the current locale. builder.appendText(ChronoField.DAY_OF_WEEK, TextStyle.FULL); } @Override public void enterPb(StrfTimeParser.PbContext ctx) { // %b The abbreviated month name according to the current locale. // %h Equivalent to %b. builder.appendText(ChronoField.MONTH_OF_YEAR, TextStyle.SHORT); } @Override public void enterPB(StrfTimeParser.PBContext ctx) { // %B The full month name according to the current locale. builder.appendText(ChronoField.MONTH_OF_YEAR, TextStyle.FULL); } @Override public void enterPc(StrfTimeParser.PcContext ctx) { // %c The preferred date and time representation for the current locale. throw new UnsupportedStrfField("%c The preferred date and time representation for the current locale."); } @Override public void enterPC(StrfTimeParser.PCContext ctx) { throw new UnsupportedStrfField("%C The century number (year/100) as a 2-digit integer."); } @Override public void enterPd(StrfTimeParser.PdContext ctx) { // %d The day of the month as a decimal number (range 01 to 31). builder.appendValue(ChronoField.DAY_OF_MONTH, 2); } @Override public void enterPD(StrfTimeParser.PDContext ctx) { // %D Equivalent to %m/%d/%y. (Yecch—for Americans only) builder .appendValue(ChronoField.MONTH_OF_YEAR, 2) .appendLiteral('/') .appendValue(ChronoField.DAY_OF_MONTH, 2) .appendLiteral('/') .appendValueReduced(ChronoField.YEAR, 2, 2, 2000); } @Override public void enterPe(StrfTimeParser.PeContext ctx) { // %e Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. builder.padNext(2, ' ').appendValue(ChronoField.DAY_OF_MONTH); } @Override public void enterPF(StrfTimeParser.PFContext ctx) { // %F Equivalent to %Y-%m-%d (the ISO 8601 date format). builder .appendValue(ChronoField.YEAR, 4) .appendLiteral('-') .appendValue(ChronoField.MONTH_OF_YEAR, 2) .appendLiteral('-') .appendValue(ChronoField.DAY_OF_MONTH, 2); } @Override public void enterPG(StrfTimeParser.PGContext ctx) { // %G The ISO 8601 week-based year (see NOTES) with century as a decimal number. // The 4-digit year corresponding to the ISO week number (see %V). // This has the same format and value as %Y, except that if the ISO week number // belongs to the previous or next year, that year is used instead. builder.appendValue(LOCAL_WEEK_FIELDS.weekBasedYear(), 4); } @Override public void enterPg(StrfTimeParser.PgContext ctx) { // %g Like %G, but without century, that is, with a 2-digit year (00–99). builder.appendValueReduced(LOCAL_WEEK_FIELDS.weekBasedYear(), 2, 2, 2000); } @Override public void enterPH(StrfTimeParser.PHContext ctx) { // %H The hour as a decimal number using a 24-hour clock (range 00 to 23). builder.appendValue(ChronoField.CLOCK_HOUR_OF_DAY, 2); } @Override public void enterPI(StrfTimeParser.PIContext ctx) { // %I The hour as a decimal number using a 12-hour clock (range 01 to 12). builder.appendValue(ChronoField.CLOCK_HOUR_OF_AMPM, 2); } @Override public void enterPj(StrfTimeParser.PjContext ctx) { // %j The day of the year as a decimal number (range 001 to 366). builder.appendValue(ChronoField.DAY_OF_YEAR, 3); } @Override public void enterPk(StrfTimeParser.PkContext ctx) { // %k The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. // (See also %H) builder.padNext(2, ' ').appendValue(ChronoField.CLOCK_HOUR_OF_DAY); } @Override public void enterPl(StrfTimeParser.PlContext ctx) { // %l The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. // (See also %I) builder.padNext(2, ' ').appendValue(ChronoField.CLOCK_HOUR_OF_AMPM); } @Override public void enterPm(StrfTimeParser.PmContext ctx) { // %m The month as a decimal number (range 01 to 12). builder.appendValue(ChronoField.MONTH_OF_YEAR, 2); } @Override public void enterPM(StrfTimeParser.PMContext ctx) { // %M The minute as a decimal number (range 00 to 59). builder.appendValue(ChronoField.MINUTE_OF_HOUR, 2); } @Override public void enterPp(StrfTimeParser.PpContext ctx) { // %p Either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale. // Noon is treated as "PM" and midnight as "AM". builder.appendText(ChronoField.AMPM_OF_DAY, TextStyle.SHORT); } private static final Map AMPM_LOWER_CASE_MAPPING = new HashMap<>(); static { AMPM_LOWER_CASE_MAPPING.put(0L, "am"); AMPM_LOWER_CASE_MAPPING.put(1L, "pm"); } @Override public void enterPP(StrfTimeParser.PPContext ctx) { // %P Like %p but in lowercase: "am" or "pm" or a corresponding string for the current locale. builder.appendText(ChronoField.AMPM_OF_DAY, AMPM_LOWER_CASE_MAPPING); } @Override public void enterPr(StrfTimeParser.PrContext ctx) { // %r The time in a.m. or p.m. notation. In the POSIX locale this is equivalent to %I:%M:%S %p. builder .appendValue(ChronoField.CLOCK_HOUR_OF_AMPM, 2) .appendLiteral(':') .appendValue(ChronoField.MINUTE_OF_HOUR, 2) .appendLiteral(':') .appendValue(ChronoField.SECOND_OF_MINUTE, 2) .appendLiteral(' ') .appendText(ChronoField.AMPM_OF_DAY, TextStyle.SHORT); } @Override public void enterPR(StrfTimeParser.PRContext ctx) { // %R The time in 24-hour notation (%H:%M). For a version including the seconds, see %T below. builder .appendValue(ChronoField.HOUR_OF_DAY, 2) .appendLiteral(':') .appendValue(ChronoField.MINUTE_OF_HOUR, 2); } @Override public void enterPs(StrfTimeParser.PsContext ctx) { // %s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). // Based upon https://stackoverflow.com/questions/36066155/datetimeformatter-for-epoch-milliseconds#answer-36069732 builder .appendValue(ChronoField.INSTANT_SECONDS, 1, 19, SignStyle.NEVER); } @Override public void enterPS(StrfTimeParser.PSContext ctx) { // %S The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds) builder .appendValue(ChronoField.SECOND_OF_MINUTE, 2); } @Override public void enterPT(StrfTimeParser.PTContext ctx) { // %T The time in 24-hour notation (%H:%M:%S). builder .appendValue(ChronoField.HOUR_OF_DAY, 2) .appendLiteral(':') .appendValue(ChronoField.MINUTE_OF_HOUR, 2) .appendLiteral(':') .appendValue(ChronoField.SECOND_OF_MINUTE, 2); } @Override public void enterPu(StrfTimeParser.PuContext ctx) { // %u The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. builder.appendValue(WeekFields.ISO.dayOfWeek(), 1); } @Override public void enterPU(StrfTimeParser.PUContext ctx) { // %U The week number of the current year as a decimal number, range 00 to 53, starting with // the first Sunday as the first day of week 01. See also %V and %W. throw new UnsupportedStrfField("%U The week number of the current year ... "); } @Override public void enterPV(StrfTimeParser.PVContext ctx) { // %V The ISO 8601 week number (see NOTES) of the current year as a decimal number, range 01 to 53, // where week 1 is the first week that has at least 4 days in the new year. See also %U and %W. builder.appendValue(WeekFields.ISO.weekOfYear()); } @Override public void enterPw(StrfTimeParser.PwContext ctx) { // %w The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u. throw new UnsupportedStrfField("%w The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u."); } @Override public void enterPW(StrfTimeParser.PWContext ctx) { // %W The week number of the current year as a decimal number, range 00 to 53, // starting with the first Monday as the first day of week 01. builder.appendValue(WeekFields.ISO.weekOfYear(), 2); } @Override public void enterPx(StrfTimeParser.PxContext ctx) { // %x The preferred date representation for the current locale without the time. throw new UnsupportedStrfField("%x The preferred date representation for the current locale without the time."); } @Override public void enterPX(StrfTimeParser.PXContext ctx) { // %X The preferred time representation for the current locale without the date. throw new UnsupportedStrfField("%X The preferred time representation for the current locale without the date."); } @Override public void enterPy(StrfTimeParser.PyContext ctx) { // %y The year as a decimal number without a century (range 00 to 99). builder.appendValueReduced(ChronoField.YEAR, 2, 2, 2000); } @Override public void enterPY(StrfTimeParser.PYContext ctx) { // %Y The year as a decimal number including the century. builder.appendValue(ChronoField.YEAR, 4); } @Override public void enterPz(StrfTimeParser.PzContext ctx) { // %z The +hhmm or -hhmm numeric timezone. builder.appendOffset("+HHMM", "+0000"); zoneWasSpecified = true; } @Override public void enterPZ(StrfTimeParser.PZContext ctx) { // %Z The timezone name or abbreviation. builder.appendZoneText(TextStyle.SHORT); zoneWasSpecified = true; } @Override public void enterPplus(StrfTimeParser.PplusContext ctx) { throw new UnsupportedStrfField("%p The date and time in date(1) format."); } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/TimeStampDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.text.DateFormatSymbols; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.format.TextStyle; import java.time.temporal.WeekFields; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; public class TimeStampDissector extends Dissector { // The default parser to what we find in the Apache httpd Logfiles // [05/Sep/2010:11:27:50 +0200] public static final String DEFAULT_APACHE_DATE_TIME_PATTERN = "dd/MMM/yyyy:HH:mm:ss ZZ"; // -------------------------------------------- private transient DateTimeFormatter formatter; private String dateTimePattern; private Locale locale; // The month abbreviations this locale supports, used in attempts in recovering parse errors. private String[] localeMonths; @SuppressWarnings("UnusedDeclaration") public TimeStampDissector() { this(DEFAULT_APACHE_DATE_TIME_PATTERN); } public TimeStampDissector(String newDateTimePattern) { this("TIME.STAMP", newDateTimePattern); } public TimeStampDissector(String inputType, String newDateTimePattern) { setInputType(inputType); if (newDateTimePattern == null || newDateTimePattern.trim().isEmpty()) { setDateTimePattern(DEFAULT_APACHE_DATE_TIME_PATTERN); } else { setDateTimePattern(newDateTimePattern); } setLocale(Locale.UK); // The default Locale that follows the ISO-8601 WeekFields and has sensible names. } public TimeStampDissector setLocale(Locale newLocale) { locale = newLocale; localeMonths = new DateFormatSymbols(locale).getShortMonths(); return this; } public Locale getLocale() { return locale; } // -------------------------------------------- @Override public boolean initializeFromSettingsParameter(String settings) { // There is only one setting for this dissector setDateTimePattern(settings); return true; // Everything went right. } // -------------------------------------------- public void setDateTimePattern(String nDateTimePattern) { this.dateTimePattern = nDateTimePattern; } protected void setFormatter(DateTimeFormatter newFormatter) { formatter = newFormatter; } protected DateTimeFormatter getFormatter() { if (formatter == null) { formatter = new DateTimeFormatterBuilder() .parseCaseInsensitive() .appendPattern(dateTimePattern) .toFormatter() .withLocale(locale); } return formatter; } @Override protected void initializeNewInstance(Dissector newInstance) { TimeStampDissector newTimeStampDissector = (TimeStampDissector) newInstance; newTimeStampDissector.setInputType(inputType); newTimeStampDissector.setDateTimePattern(dateTimePattern); newTimeStampDissector.setLocale(locale); } // -------------------------------------------- private String inputType = "TIME.STAMP"; @Override public String getInputType() { return inputType; } @Override public final void setInputType(String nInputType) { inputType = nInputType; } // -------------------------------------------- @Override public List getPossibleOutput() { List result = new ArrayList<>(); // As parsed result.add("TIME.DAY:day"); result.add("TIME.MONTHNAME:monthname"); result.add("TIME.MONTH:month"); result.add("TIME.WEEK:weekofweekyear"); result.add("TIME.YEAR:weekyear"); result.add("TIME.YEAR:year"); result.add("TIME.HOUR:hour"); result.add("TIME.MINUTE:minute"); result.add("TIME.SECOND:second"); result.add("TIME.MILLISECOND:millisecond"); result.add("TIME.MICROSECOND:microsecond"); result.add("TIME.NANOSECOND:nanosecond"); result.add("TIME.DATE:date"); // yyyy-MM-dd result.add("TIME.TIME:time"); // HH:mm:ss // Timezone independent result.add("TIME.ZONE:timezone"); result.add("TIME.EPOCH:epoch"); // In UTC timezone result.add("TIME.DAY:day_utc"); result.add("TIME.MONTHNAME:monthname_utc"); result.add("TIME.MONTH:month_utc"); result.add("TIME.WEEK:weekofweekyear_utc"); result.add("TIME.YEAR:weekyear_utc"); result.add("TIME.YEAR:year_utc"); result.add("TIME.HOUR:hour_utc"); result.add("TIME.MINUTE:minute_utc"); result.add("TIME.SECOND:second_utc"); result.add("TIME.MILLISECOND:millisecond_utc"); result.add("TIME.MICROSECOND:microsecond_utc"); result.add("TIME.NANOSECOND:nanosecond_utc"); result.add("TIME.DATE:date_utc"); // yyyy-MM-dd result.add("TIME.TIME:time_utc"); // HH:mm:ss return result; } // -------------------------------------------- private boolean wantAnyAsParsed = false; private boolean wantAnyUTC = false; private boolean wantAnyTZIndependent = false; // As parsed private boolean wantDay = false; private boolean wantMonthname = false; private boolean wantMonth = false; private boolean wantWeekOfWeekYear = false; private boolean wantWeekYear = false; private boolean wantYear = false; private boolean wantHour = false; private boolean wantMinute = false; private boolean wantSecond = false; private boolean wantMillisecond = false; private boolean wantMicrosecond = false; private boolean wantNanosecond = false; private boolean wantDate = false; private boolean wantTime = false; // Timezone independent private boolean wantTimezone = false; private boolean wantEpoch = false; // In UTC timezone private boolean wantDayUTC = false; private boolean wantMonthnameUTC = false; private boolean wantMonthUTC = false; private boolean wantWeekOfWeekYearUTC = false; private boolean wantWeekYearUTC = false; private boolean wantYearUTC = false; private boolean wantHourUTC = false; private boolean wantMinuteUTC = false; private boolean wantSecondUTC = false; private boolean wantMillisecondUTC = false; private boolean wantMicrosecondUTC = false; private boolean wantNanosecondUTC = false; private boolean wantDateUTC = false; private boolean wantTimeUTC = false; @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { String name = extractFieldName(inputname, outputname); switch (name) { // As parsed case "day": wantDay = true; return STRING_OR_LONG; case "monthname": wantMonthname = true; return STRING_ONLY; case "month": wantMonth = true; return STRING_OR_LONG; case "weekofweekyear": wantWeekOfWeekYear = true; return STRING_OR_LONG; case "weekyear": wantWeekYear = true; return STRING_OR_LONG; case "year": wantYear = true; return STRING_OR_LONG; case "hour": wantHour = true; return STRING_OR_LONG; case "minute": wantMinute = true; return STRING_OR_LONG; case "second": wantSecond = true; return STRING_OR_LONG; case "millisecond": wantMillisecond = true; return STRING_OR_LONG; case "microsecond": wantMicrosecond = true; return STRING_OR_LONG; case "nanosecond": wantNanosecond = true; return STRING_OR_LONG; case "date": wantDate = true; return STRING_ONLY; case "time": wantTime = true; return STRING_ONLY; // Timezone independent case "timezone": wantTimezone = true; return STRING_ONLY; case "epoch": wantEpoch = true; return STRING_OR_LONG; // In UTC timezone case "day_utc": wantDayUTC = true; return STRING_OR_LONG; case "monthname_utc": wantMonthnameUTC = true; return STRING_ONLY; case "month_utc": wantMonthUTC = true; return STRING_OR_LONG; case "weekofweekyear_utc": wantWeekOfWeekYearUTC = true; return STRING_OR_LONG; case "weekyear_utc": wantWeekYearUTC = true; return STRING_OR_LONG; case "year_utc": wantYearUTC = true; return STRING_OR_LONG; case "hour_utc": wantHourUTC = true; return STRING_OR_LONG; case "minute_utc": wantMinuteUTC = true; return STRING_OR_LONG; case "second_utc": wantSecondUTC = true; return STRING_OR_LONG; case "millisecond_utc": wantMillisecondUTC = true; return STRING_OR_LONG; case "microsecond_utc": wantMicrosecondUTC = true; return STRING_OR_LONG; case "nanosecond_utc": wantNanosecondUTC = true; return STRING_OR_LONG; case "date_utc": wantDateUTC = true; return STRING_ONLY; case "time_utc": wantTimeUTC = true; return STRING_ONLY; default: return NO_CASTS; } } // -------------------------------------------- @Override public void prepareForRun() { // As parsed wantAnyAsParsed = wantDay || wantMonthname || wantMonth || wantWeekOfWeekYear || wantWeekYear || wantYear || wantHour || wantMinute || wantSecond || wantMillisecond || wantMicrosecond || wantNanosecond || wantDate || wantTime; // Timezone independent wantAnyTZIndependent = wantTimezone || wantEpoch; // In UTC timezone wantAnyUTC = wantDayUTC || wantMonthnameUTC || wantMonthUTC || wantWeekOfWeekYearUTC || wantWeekYearUTC || wantYearUTC || wantHourUTC || wantMinuteUTC || wantSecondUTC || wantMillisecondUTC || wantMicrosecondUTC || wantNanosecondUTC || wantDateUTC || wantTimeUTC; } // -------------------------------------------- private static final DateTimeFormatter ISO_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); private static final DateTimeFormatter ISO_TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss"); @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(getInputType(), inputname); dissect(field, parsable, inputname); } private ZonedDateTime parse(String fieldValue) throws DateTimeParseException { ZonedDateTime dateTime; try { dateTime = getFormatter().parse(fieldValue, ZonedDateTime::from); } catch (DateTimeParseException dtpe) { // Some parse errors can be fixed. fieldValue = attemptRecoverParseError(fieldValue, dtpe); // Retry parsing with an adjusted fieldValue. dateTime = getFormatter().parse(fieldValue, ZonedDateTime::from); } return dateTime; } protected void dissect(ParsedField field, final Parsable parsable, final String inputname) throws DissectionFailure { String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()) { return; // Nothing to do here } ZonedDateTime dateTime; try { dateTime = parse(fieldValue); } catch (DateTimeParseException dtpe) { // If this fails it is not a line specific problem but a configuration problem. throw new DissectionFailure(dtpe.getMessage()+ "\n 10 20 30 40 50 60 70 80 90 100 110 120" + "\n_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_" + "\n"+fieldValue+"\n\n"+formatter.toString(), dtpe); } if (wantAnyTZIndependent) { // Timezone independent if (wantTimezone) { parsable.addDissection(inputname, "TIME.ZONE", "timezone", dateTime.getZone().getDisplayName(TextStyle.FULL, locale)); } if (wantEpoch) { parsable.addDissection(inputname, "TIME.EPOCH", "epoch", dateTime.toInstant().toEpochMilli()); } } if (wantAnyAsParsed) { LocalDateTime localDateTime = dateTime.toLocalDateTime(); // As parsed if (wantDay) { parsable.addDissection(inputname, "TIME.DAY", "day", localDateTime.getDayOfMonth()); } if (wantMonthname) { parsable.addDissection(inputname, "TIME.MONTHNAME", "monthname", localDateTime.getMonth().getDisplayName(TextStyle.FULL, locale)); } if (wantMonth) { parsable.addDissection(inputname, "TIME.MONTH", "month", localDateTime.getMonth().getValue()); } if (wantWeekOfWeekYear) { parsable.addDissection(inputname, "TIME.WEEK", "weekofweekyear", localDateTime.get(WeekFields.of(locale).weekOfWeekBasedYear())); } if (wantWeekYear) { parsable.addDissection(inputname, "TIME.YEAR", "weekyear", localDateTime.get(WeekFields.of(locale).weekBasedYear())); } if (wantYear) { parsable.addDissection(inputname, "TIME.YEAR", "year", localDateTime.getYear()); } if (wantHour) { parsable.addDissection(inputname, "TIME.HOUR", "hour", localDateTime.getHour()); } if (wantMinute) { parsable.addDissection(inputname, "TIME.MINUTE", "minute", localDateTime.getMinute()); } if (wantSecond) { parsable.addDissection(inputname, "TIME.SECOND", "second", localDateTime.getSecond()); } if (wantMillisecond) { parsable.addDissection(inputname, "TIME.MILLISECOND", "millisecond", localDateTime.getNano() / 1000000L); } if (wantMicrosecond) { parsable.addDissection(inputname, "TIME.MICROSECOND", "microsecond", localDateTime.getNano() / 1000L); } if (wantNanosecond) { parsable.addDissection(inputname, "TIME.NANOSECOND", "nanosecond", localDateTime.getNano()); } if (wantDate) { parsable.addDissection(inputname, "TIME.DATE", "date", localDateTime.format(ISO_DATE_FORMATTER)); } if (wantTime) { parsable.addDissection(inputname, "TIME.TIME", "time", localDateTime.format(ISO_TIME_FORMATTER)); } } if (wantAnyUTC) { // In UTC timezone ZonedDateTime zonedDateTime = dateTime.withZoneSameInstant(ZoneOffset.UTC); if (wantDayUTC) { parsable.addDissection(inputname, "TIME.DAY", "day_utc", zonedDateTime.getDayOfMonth()); } if (wantMonthnameUTC) { parsable.addDissection(inputname, "TIME.MONTHNAME", "monthname_utc", zonedDateTime.getMonth().getDisplayName(TextStyle.FULL, locale)); } if (wantMonthUTC) { parsable.addDissection(inputname, "TIME.MONTH", "month_utc", zonedDateTime.getMonthValue()); } if (wantWeekOfWeekYearUTC) { parsable.addDissection(inputname, "TIME.WEEK", "weekofweekyear_utc", zonedDateTime.get(WeekFields.ISO.weekOfWeekBasedYear())); } if (wantWeekYearUTC) { parsable.addDissection(inputname, "TIME.YEAR", "weekyear_utc", zonedDateTime.get(WeekFields.ISO.weekBasedYear())); } if (wantYearUTC) { parsable.addDissection(inputname, "TIME.YEAR", "year_utc", zonedDateTime.getYear()); } if (wantHourUTC) { parsable.addDissection(inputname, "TIME.HOUR", "hour_utc", zonedDateTime.getHour()); } if (wantMinuteUTC) { parsable.addDissection(inputname, "TIME.MINUTE", "minute_utc", zonedDateTime.getMinute()); } if (wantSecondUTC) { parsable.addDissection(inputname, "TIME.SECOND", "second_utc", zonedDateTime.getSecond()); } if (wantMillisecondUTC) { parsable.addDissection(inputname, "TIME.MILLISECOND", "millisecond_utc", zonedDateTime.getNano() / 1000000L); } if (wantMicrosecondUTC) { parsable.addDissection(inputname, "TIME.MICROSECOND", "microsecond_utc", zonedDateTime.getNano() / 1000L); } if (wantNanosecondUTC) { parsable.addDissection(inputname, "TIME.NANOSECOND", "nanosecond_utc", zonedDateTime.getNano()); } if (wantDateUTC) { parsable.addDissection(inputname, "TIME.DATE", "date_utc", zonedDateTime.format(ISO_DATE_FORMATTER)); } if (wantTimeUTC) { parsable.addDissection(inputname, "TIME.TIME", "time_utc", zonedDateTime.format(ISO_TIME_FORMATTER)); } } } // -------------------------------------------- // Get the month abbreviations in (American) "English" as commonly used in logging. final String[] englishMonths = new String[] { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec", }; // Performance optimization final String[] pqEnglishMonths = new String[] { Pattern.quote("jan"), Pattern.quote("feb"), Pattern.quote("mar"), Pattern.quote("apr"), Pattern.quote("may"), Pattern.quote("jun"), Pattern.quote("jul"), Pattern.quote("aug"), Pattern.quote("sep"), Pattern.quote("oct"), Pattern.quote("nov"), Pattern.quote("dec"), }; // In some cases we have these specials final String[] englishMonths4 = new String[] { null, null, null, null, null, "june", "july", null, "sept", null, null, null, null, }; // Performance optimization final String[] pqEnglishMonths4 = new String[] { null, null, null, null, null, Pattern.quote("june"), Pattern.quote("july"), null, Pattern.quote("sept"), null, null, null, null, }; private String attemptRecoverParseError(String fieldValue, DateTimeParseException dtpe) { // Error handling: We may have the wrong name for the month here. // Unicode CLDR has for different locales different "short" names // for some months: Jun/June, Jul/July and Sep/Sept. // At this point there is no parser I have that can handle these variations // transparently, so in case of an exception: Try to apply a fix and redo. // See // https://stackoverflow.com/questions/70928852/customize-a-locale-in-java/ // https://unicode-org.atlassian.net/browse/CLDR-15317 fieldValue = fieldValue.toLowerCase(Locale.ROOT); String updatedFieldValue = fieldValue; // Fix idea: Convert some of the "well known" ways the Months names appear // into what the current Locale expects. // FIXME: This does NOT fix all cases where this goes wrong. for (int i = 0; i < englishMonths.length; i++) { String value = englishMonths4[i]; if (value != null && updatedFieldValue.contains(value)) { updatedFieldValue = updatedFieldValue .replaceAll(pqEnglishMonths4[i], localeMonths[i]); continue; } value = englishMonths[i]; if (value != null && updatedFieldValue.contains(value)) { updatedFieldValue = updatedFieldValue .replaceAll(pqEnglishMonths[i], localeMonths[i]); } } if (fieldValue.equals(updatedFieldValue)) { // No changes were actually applied: Apparently this was something different. throw dtpe; } return updatedFieldValue; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/geoip/AbstractGeoIPDissector.java ================================================ /* * Apache HTTPD logparsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.geoip; import com.maxmind.db.CHMCache; import com.maxmind.db.Reader; import com.maxmind.geoip2.DatabaseReader; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.UnknownHostException; public abstract class AbstractGeoIPDissector extends Dissector { static final String INPUT_TYPE = "IP"; String databaseFileName; public AbstractGeoIPDissector() { } public AbstractGeoIPDissector(String databaseFileName) { this.databaseFileName = databaseFileName; } @Override public String getInputType() { return INPUT_TYPE; } // -------------------------------------------- @Override public boolean initializeFromSettingsParameter(String settings) { databaseFileName = settings; return true; // Everything went right. } // -------------------------------------------- @Override protected void initializeNewInstance(Dissector newInstance) { newInstance.initializeFromSettingsParameter(databaseFileName); } // -------------------------------------------- protected DatabaseReader reader; @Override public void prepareForRun() throws InvalidDissectorException { // This creates the DatabaseReader object, which should be reused across lookups. try { reader = new DatabaseReader .Builder(openDatabaseFile(databaseFileName)) .fileMode(Reader.FileMode.MEMORY) .withCache(new CHMCache()) .build(); } catch (IOException e) { throw new InvalidDissectorException(this.getClass().getCanonicalName() + ":" + e.getMessage()); } } protected InputStream openDatabaseFile(String filename) throws FileNotFoundException { return new FileInputStream(filename); } // -------------------------------------------- @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(INPUT_TYPE, inputname); String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()) { return; // Nothing to do here } InetAddress ipAddress; try { ipAddress = InetAddress.getByName(fieldValue); } catch (UnknownHostException e) { return; } dissect(parsable, inputname, ipAddress); } // -------------------------------------------- abstract void dissect(Parsable parsable, String inputname, InetAddress ipAddress) throws DissectionFailure; } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/geoip/GeoIPASNDissector.java ================================================ /* * Apache HTTPD logparsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.geoip; import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.model.AsnResponse; import com.maxmind.geoip2.model.IspResponse; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.io.IOException; import java.net.InetAddress; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; public class GeoIPASNDissector extends AbstractGeoIPDissector { @SuppressWarnings("unused") // Used via reflection public GeoIPASNDissector() { super(); } public GeoIPASNDissector(String databaseFileName) { super(databaseFileName); } @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("ASN:asn.number"); result.add("STRING:asn.organization"); return result; } private boolean wantAsnNumber = false; private boolean wantAsnOrganization = false; @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { String name = extractFieldName(inputname, outputname); switch (name) { case "asn.number": wantAsnNumber = true; return STRING_OR_LONG; case "asn.organization": wantAsnOrganization = true; return STRING_ONLY; default: return NO_CASTS; } } // -------------------------------------------- public void dissect(final Parsable parsable, final String inputname, final InetAddress ipAddress) throws DissectionFailure { AsnResponse response; try { response = reader.asn(ipAddress); } catch (IOException | GeoIp2Exception e) { return; } extractAsnFields(parsable, inputname, response); } protected void extractAsnFields(final Parsable parsable, final String inputname, AsnResponse response) throws DissectionFailure { if (wantAsnNumber) { parsable.addDissection(inputname, "ASN", "asn.number", response.autonomousSystemNumber()); } if (wantAsnOrganization) { parsable.addDissection(inputname, "STRING", "asn.organization", response.autonomousSystemOrganization()); } } // The EXACT same function but now for an IspResponse ... protected void extractAsnFields(final Parsable parsable, final String inputname, IspResponse response) throws DissectionFailure { if (wantAsnNumber) { parsable.addDissection(inputname, "ASN", "asn.number", response.autonomousSystemNumber()); } if (wantAsnOrganization) { parsable.addDissection(inputname, "STRING", "asn.organization", response.autonomousSystemOrganization()); } } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/geoip/GeoIPCityDissector.java ================================================ /* * Apache HTTPD logparsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.geoip; import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.model.CityResponse; import com.maxmind.geoip2.record.City; import com.maxmind.geoip2.record.Location; import com.maxmind.geoip2.record.Postal; import com.maxmind.geoip2.record.Subdivision; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.io.IOException; import java.net.InetAddress; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_DOUBLE; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; public class GeoIPCityDissector extends GeoIPCountryDissector { @SuppressWarnings("unused") // Used via reflection public GeoIPCityDissector() { super(); } public GeoIPCityDissector(String databaseFileName) { super(databaseFileName); } @Override public List getPossibleOutput() { List result = super.getPossibleOutput(); result.add("STRING:subdivision.name"); result.add("STRING:subdivision.iso"); result.add("STRING:city.name"); result.add("NUMBER:city.confidence"); result.add("NUMBER:city.geonameid"); result.add("STRING:postal.code"); result.add("NUMBER:postal.confidence"); result.add("STRING:location.latitude"); result.add("STRING:location.longitude"); result.add("STRING:location.timezone"); result.add("NUMBER:location.accuracyradius"); return result; } private boolean wantSubdivisionName = false; private boolean wantSubdivisionIso = false; private boolean wantAnySubdivision = false; private boolean wantCityName = false; private boolean wantCityConfidence = false; private boolean wantCityGeoNameId = false; private boolean wantAnyCity = false; private boolean wantPostalCode = false; private boolean wantPostalConfidence = false; private boolean wantAnyPostal = false; private boolean wantLocationLatitude = false; private boolean wantLocationLongitude = false; private boolean wantLocationTimezone = false; private boolean wantLocationAccuracyRadius = false; private boolean wantAnyLocation = false; @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { EnumSet result = super.prepareForDissect(inputname, outputname); if (!result.isEmpty()) { return result; } String name = extractFieldName(inputname, outputname); switch (name) { case "subdivision.name": wantSubdivisionName = true; wantAnySubdivision = true; return STRING_ONLY; case "subdivision.iso": wantSubdivisionIso = true; wantAnySubdivision = true; return STRING_ONLY; // --------------------------------- case "city.name": wantCityName = true; wantAnyCity = true; return STRING_ONLY; case "city.confidence": wantCityConfidence = true; wantAnyCity = true; return STRING_OR_LONG; case "city.geonameid": wantCityGeoNameId = true; wantAnyCity = true; return STRING_OR_LONG; // --------------------------------- case "postal.code": wantPostalCode = true; wantAnyPostal = true; return STRING_ONLY; case "postal.confidence": wantPostalConfidence = true; wantAnyPostal = true; return STRING_OR_LONG; // --------------------------------- case "location.latitude": wantLocationLatitude = true; wantAnyLocation = true; return STRING_OR_DOUBLE; case "location.longitude": wantLocationLongitude = true; wantAnyLocation = true; return STRING_OR_DOUBLE; case "location.accuracyradius": wantLocationAccuracyRadius = true; wantAnyLocation = true; return STRING_OR_LONG; case "location.timezone": wantLocationTimezone = true; wantAnyLocation = true; return STRING_ONLY; default: return NO_CASTS; } } // -------------------------------------------- public void dissect(final Parsable parsable, final String inputname, final InetAddress ipAddress) throws DissectionFailure { // City is the 'Country' + more details. CityResponse response; try { response = reader.city(ipAddress); } catch (IOException | GeoIp2Exception e) { return; } extractCityResponseFields(parsable, inputname, response); } protected void extractCityResponseFields(final Parsable parsable, final String inputname, CityResponse response) throws DissectionFailure { super.extractCityResponseFields(parsable, inputname, response); if (wantAnySubdivision) { extractSubdivisionFields(parsable, inputname, response.mostSpecificSubdivision()); } if (wantAnyCity) { extractCityFields(parsable, inputname, response.city()); } if (wantAnyPostal) { extractPostalFields(parsable, inputname, response.postal()); } if (wantAnyLocation) { extractLocationFields(parsable, inputname, response.location()); } } protected void extractSubdivisionFields(final Parsable parsable, final String inputname, Subdivision subdivision) throws DissectionFailure { if (subdivision != null) { if (wantSubdivisionName) { parsable.addDissection(inputname, "STRING", "subdivision.name", subdivision.name()); } if (wantSubdivisionIso) { parsable.addDissection(inputname, "STRING", "subdivision.iso", subdivision.isoCode()); } } } protected void extractCityFields(final Parsable parsable, final String inputname, City city) throws DissectionFailure { if (city != null) { if (wantCityName) { parsable.addDissection(inputname, "STRING", "city.name", city.name()); } if (wantCityConfidence) { parsable.addDissection(inputname, "NUMBER", "city.confidence", city.confidence()); } if (wantCityGeoNameId) { parsable.addDissection(inputname, "NUMBER", "city.geonameid", city.geonameId()); } } } protected void extractPostalFields(final Parsable parsable, final String inputname, Postal postal) throws DissectionFailure { if (postal != null) { if (wantPostalCode) { parsable.addDissection(inputname, "STRING", "postal.code", postal.code()); } if (wantPostalConfidence) { parsable.addDissection(inputname, "NUMBER", "postal.confidence", postal.confidence()); } } } protected void extractLocationFields(final Parsable parsable, final String inputname, Location location) throws DissectionFailure { if (location != null) { if (wantLocationLatitude) { parsable.addDissection(inputname, "STRING", "location.latitude", location.latitude()); } if (wantLocationLongitude) { parsable.addDissection(inputname, "STRING", "location.longitude", location.longitude()); } if (wantLocationTimezone) { parsable.addDissection(inputname, "STRING", "location.timezone", location.timeZone()); } if (wantLocationAccuracyRadius) { parsable.addDissection(inputname, "NUMBER", "location.accuracyradius", location.accuracyRadius()); } } } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/geoip/GeoIPCountryDissector.java ================================================ /* * Apache HTTPD logparsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.geoip; import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.model.CityResponse; import com.maxmind.geoip2.model.CountryResponse; import com.maxmind.geoip2.record.Continent; import com.maxmind.geoip2.record.Country; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.io.IOException; import java.net.InetAddress; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; public class GeoIPCountryDissector extends AbstractGeoIPDissector { @SuppressWarnings("unused") // Used via reflection public GeoIPCountryDissector() { super(); } public GeoIPCountryDissector(String databaseFileName) { super(databaseFileName); } @Override public List getPossibleOutput() { List result = new ArrayList<>(); result.add("STRING:continent.name"); result.add("STRING:continent.code"); result.add("STRING:country.name"); result.add("STRING:country.iso"); result.add("NUMBER:country.getconfidence"); result.add("BOOLEAN:country.isineuropeanunion"); return result; } private boolean wantContinentName = false; private boolean wantContinentCode = false; private boolean wantAnyContinent = false; private boolean wantCountryName = false; private boolean wantCountryIso = false; private boolean wantCountryGetConfidence = false; private boolean wantCountryIsInEuropeanUnion = false; private boolean wantAnyCountry = false; @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { String name = extractFieldName(inputname, outputname); switch (name) { case "continent.name": wantContinentName = true; wantAnyContinent = true; return STRING_ONLY; case "continent.code": wantContinentCode = true; wantAnyContinent = true; return STRING_ONLY; case "country.name": wantCountryName = true; wantAnyCountry = true; return STRING_ONLY; case "country.iso": wantCountryIso = true; wantAnyCountry = true; return STRING_ONLY; case "country.getconfidence": wantCountryGetConfidence = true; wantAnyCountry = true; return STRING_OR_LONG; case "country.isineuropeanunion": wantCountryIsInEuropeanUnion = true; wantAnyCountry = true; return STRING_OR_LONG; default: return NO_CASTS; } } // -------------------------------------------- public void dissect(final Parsable parsable, final String inputname, final InetAddress ipAddress) throws DissectionFailure { CountryResponse response; try { response = reader.country(ipAddress); } catch (IOException | GeoIp2Exception e) { return; } extractCountryResponseFields(parsable, inputname, response); } protected void extractCountryResponseFields(final Parsable parsable, final String inputname, CountryResponse response) throws DissectionFailure { if (wantAnyContinent) { extractContinentFields(parsable, inputname, response.continent()); } if (wantAnyCountry) { extractCountryFields(parsable, inputname, response.country()); } } // -------------------------------------------- // The EXACT same function but now for a CityResponse ... protected void extractCityResponseFields(final Parsable parsable, final String inputname, CityResponse response) throws DissectionFailure { if (wantAnyContinent) { extractContinentFields(parsable, inputname, response.continent()); } if (wantAnyCountry) { extractCountryFields(parsable, inputname, response.country()); } } protected void extractContinentFields(final Parsable parsable, final String inputname, Continent continent) throws DissectionFailure { if (continent != null) { if (wantContinentName) { parsable.addDissection(inputname, "STRING", "continent.name", continent.name()); } if (wantContinentCode) { parsable.addDissection(inputname, "STRING", "continent.code", continent.code()); } } } protected void extractCountryFields(final Parsable parsable, final String inputname, Country country) throws DissectionFailure { if (country != null) { if (wantCountryName) { parsable.addDissection(inputname, "STRING", "country.name", country.name()); } if (wantCountryIso) { parsable.addDissection(inputname, "STRING", "country.iso", country.isoCode()); } if (wantCountryGetConfidence) { parsable.addDissection(inputname, "NUMBER", "country.getconfidence", country.confidence()); } if (wantCountryIsInEuropeanUnion) { parsable.addDissection(inputname, "BOOLEAN", "country.isineuropeanunion", country.isInEuropeanUnion() ? 1L : 0L); } } } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/geoip/GeoIPISPDissector.java ================================================ /* * Apache HTTPD logparsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.geoip; import com.maxmind.geoip2.exception.GeoIp2Exception; import com.maxmind.geoip2.model.IspResponse; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.exceptions.DissectionFailure; import java.io.IOException; import java.net.InetAddress; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.NO_CASTS; import static nl.basjes.parse.core.Casts.STRING_ONLY; public class GeoIPISPDissector extends GeoIPASNDissector { @SuppressWarnings("unused") // Used via reflection public GeoIPISPDissector() { super(); } public GeoIPISPDissector(String databaseFileName) { super(databaseFileName); } @Override public List getPossibleOutput() { List result = super.getPossibleOutput(); result.add("STRING:isp.name"); result.add("STRING:isp.organization"); return result; } private boolean wantIspName = false; private boolean wantIspOrganization = false; @Override public EnumSet prepareForDissect(final String inputname, final String outputname) { EnumSet result = super.prepareForDissect(inputname, outputname); if (!result.isEmpty()) { return result; } String name = extractFieldName(inputname, outputname); switch (name) { case "isp.name": wantIspName = true; return STRING_ONLY; case "isp.organization": wantIspOrganization = true; return STRING_ONLY; default: return NO_CASTS; } } // -------------------------------------------- public void dissect(final Parsable parsable, final String inputname, final InetAddress ipAddress) throws DissectionFailure { IspResponse response; try { response = reader.isp(ipAddress); } catch (IOException | GeoIp2Exception e) { return; } extractAsnFields(parsable, inputname, response); extractIspFields(parsable, inputname, response); } protected void extractIspFields(final Parsable parsable, final String inputname, IspResponse response) throws DissectionFailure { if (wantIspName) { parsable.addDissection(inputname, "STRING", "isp.name", response.isp()); } if (wantIspOrganization) { parsable.addDissection(inputname, "STRING", "isp.organization", response.organization()); } } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/CoreLogModule.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.httpdlog.dissectors.tokenformat.NamedTokenParser; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenFormatDissector; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import java.util.ArrayList; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_CLF_IP; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_CLF_NUMBER; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_HEXDIGIT; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_HEXNUMBER; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NO_SPACE_STRING; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NUMBER; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NUMBER_DECIMAL; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STANDARD_TIME_ISO8601; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STANDARD_TIME_US; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STRING; // Implement the variables described here: // https://nginx.org/en/docs/http/ngx_http_log_module.html#log_format // https://nginx.org/en/docs/http/ngx_http_core_module.html#variables public class CoreLogModule implements NginxModule { @Override public List getTokenParsers() { List parsers = new ArrayList<>(60); // ------- // $bytes_sent // number of bytes sent to a client (1.3.8, 1.2.5) parsers.add(new TokenParser("$bytes_sent", "response.bytes", "BYTES", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // $bytes_received // number of bytes received from a client (1.11.4) parsers.add(new TokenParser("$bytes_received", "request.bytes", "BYTES", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // $connection // connection serial number (1.3.8, 1.2.5) parsers.add(new TokenParser("$connection", "connection.serial_number", "NUMBER", STRING_OR_LONG, FORMAT_CLF_NUMBER, -1)); // ------- // $connection_requests // current number of requests made through a connection (1.3.8, 1.2.5) parsers.add(new TokenParser("$connection_requests", "connection.requestnr", "NUMBER", STRING_OR_LONG, FORMAT_CLF_NUMBER)); // ------- // $msec // time in seconds with a milliseconds resolution at the time of the log write // Example value: 1483455396.639 parsers.add(new TokenParser("$msec", "request.receive.time.epoch", "TIME.EPOCH_SECOND_MILLIS", STRING_ONLY, "[0-9]+\\.[0-9][0-9][0-9]")); // ------- // $status // response status parsers.add(new TokenParser("$status", "request.status.last", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $time_iso8601 // local time in the ISO 8601 standard format (1.3.12, 1.2.7) parsers.add(new TokenParser("$time_iso8601", "request.receive.time", "TIME.ISO8601", STRING_ONLY, FORMAT_STANDARD_TIME_ISO8601)); // ------- // $time_local // local time in the Common Log Format (1.3.12, 1.2.7) parsers.add(new TokenParser("$time_local", "request.receive.time", "TIME.STAMP", STRING_ONLY, FORMAT_STANDARD_TIME_US)); // https://nginx.org/en/docs/http/ngx_http_core_module.html#var_bytes_sent // ------- // $arg_name // argument name in the request line parsers.add(new NamedTokenParser("\\$arg_([a-z0-9\\-\\_]*)", "request.firstline.uri.query.", "STRING", STRING_ONLY, FORMAT_STRING)); // ------- // $is_args // “?” if a request line has arguments, or an empty string otherwise parsers.add(new TokenParser("$is_args", "request.firstline.uri.is_args", "STRING", STRING_ONLY, FORMAT_STRING)); // ------- // $args // arguments in the request line parsers.add(new TokenParser("$args", "request.firstline.uri.query", "HTTP.QUERYSTRING", STRING_ONLY, FORMAT_STRING)); // ------- // $query_string // same as $args parsers.add(new TokenParser("$query_string", "request.firstline.uri.query", "HTTP.QUERYSTRING", STRING_ONLY, FORMAT_STRING)); // ------- // $body_bytes_sent // number of bytes sent to a client, not counting the response header; this variable is compatible with // the “%B” parameter of the mod_log_config Apache module parsers.add(new TokenParser("$body_bytes_sent", "response.body.bytes", "BYTES", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // $content_length // “Content-Length” request header field parsers.add(new TokenParser("$content_length", "request.header.content_length", "HTTP.HEADER", STRING_ONLY, FORMAT_STRING)); // ------- // $content_type // “Content-Type” request header field parsers.add(new TokenParser("$content_type", "request.header.content_type", "HTTP.HEADER", STRING_ONLY, FORMAT_STRING)); // ------- // $cookie_name // the name cookie parsers.add(new NamedTokenParser("\\$cookie_([a-z0-9\\-_]*)", "request.cookies.", "HTTP.COOKIE", STRING_ONLY, FORMAT_STRING)); // ------- // $document_root // root or alias directive’s value for the current request parsers.add(new TokenParser("$document_root", "request.firstline.document_root", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $realpath_root // an absolute pathname corresponding to the root or alias directive’s value for the current request, // with all symbolic links resolved to real paths parsers.add(new TokenParser("$realpath_root", "request.firstline.realpath_root", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $host // in this order of precedence: host name from the request line, or host name from the “Host” request header field, // or the server name matching a request parsers.add(new TokenParser("$host", "connection.server.name", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING, -1)); // ------- // $hostname // host name parsers.add(new TokenParser("$hostname", "connection.client.host", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $http_ // arbitrary request header field; the last part of a variable name is the field name converted // to lower case with dashes replaced by underscores parsers.add(new NamedTokenParser("\\$http_([a-z0-9\\-_]*)", "request.header.", "HTTP.HEADER", STRING_ONLY, FORMAT_STRING)); parsers.add(new TokenParser("$http_user_agent", "request.user-agent", "HTTP.USERAGENT", STRING_ONLY, FORMAT_STRING, 1)); parsers.add(new TokenParser("$http_referer", "request.referer", "HTTP.URI", STRING_ONLY, FORMAT_NO_SPACE_STRING, 1)); // ------- // $https // “on” if connection operates in SSL mode, or an empty string otherwise parsers.add(new TokenParser("$https", "connection.https", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $limit_rate // setting this variable enables response rate limiting; see limit_rate parsers.add(new TokenFormatDissector.NotImplementedTokenParser("$limit_rate", "nginx_parameter_not_intended_for_logging", FORMAT_NO_SPACE_STRING, 0)); // ------- // $nginx_version // nginx version parsers.add(new TokenParser("$nginx_version", "server.nginx.version", "STRING", STRING_ONLY, TokenParser.FORMAT_STRING)); // ------- // $pid // PID of the worker process parsers.add(new TokenParser("$pid", "connection.server.child.processid", "NUMBER", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // $protocol // protocol used to communicate with the client: TCP or UDP (1.11.4) parsers.add(new TokenParser("$protocol", "connection.protocol", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $pipe // “p” if request was pipelined, “.” otherwise (1.3.12, 1.2.7) parsers.add(new TokenParser("$pipe", "connection.nginx.pipe", "STRING", STRING_ONLY, ".")); // ------- // $proxy_protocol_addr // client address from the PROXY protocol header, or an empty string otherwise (1.5.12) // The PROXY protocol must be previously enabled by setting the proxy_protocol parameter // in the listen directive. parsers.add(new TokenParser("$proxy_protocol_addr", "connection.client.proxy.host", "IP", STRING_OR_LONG, FORMAT_CLF_IP)); // $proxy_protocol_port // client port from the PROXY protocol header, or an empty string otherwise (1.11.4) parsers.add(new TokenParser("$proxy_protocol_port", "connection.client.proxy.port", "PORT", STRING_OR_LONG, FORMAT_CLF_NUMBER)); // ------- // $remote_addr // client address parsers.add(new TokenParser("$remote_addr", "connection.client.host", "IP", STRING_OR_LONG, FORMAT_CLF_IP)); // ------- // $binary_remote_addr // client address in a binary form, value’s length is always 4 bytes String formatHexByte = "\\\\x" + FORMAT_HEXDIGIT + FORMAT_HEXDIGIT; parsers.add(new TokenParser("$binary_remote_addr", "connection.client.host", "IP_BINARY", STRING_OR_LONG, formatHexByte + formatHexByte + formatHexByte + formatHexByte)); // ------- // $remote_port // client port parsers.add(new TokenParser("$remote_port", "connection.client.port", "PORT", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // $remote_user // user name supplied with the Basic authentication parsers.add(new TokenParser("$remote_user", "connection.client.user", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $request // full original request line parsers.add(new TokenParser("$request", "request.firstline", "HTTP.FIRSTLINE", STRING_ONLY, FORMAT_STRING, -2)); // ------- // $request_body // request body // The variable’s value is made available in locations processed by the proxy_pass, // fastcgi_pass, uwsgi_pass, and scgi_pass directives. parsers.add(new TokenFormatDissector.NotImplementedTokenParser("$request_body", "nginx_parameter_not_intended_for_logging", FORMAT_STRING, -1)); // ------- // $request_body_file // name of a temporary file with the request body // At the end of processing, the file needs to be removed. To always write the request body to a file, // client_body_in_file_only needs to be enabled. When the name of a temporary file is passed in a proxied request // or in a request to a FastCGI/uwsgi/SCGI server, passing the request body should be disabled by the // proxy_pass_request_body off, fastcgi_pass_request_body off, uwsgi_pass_request_body off, or // scgi_pass_request_body off directives, respectively. parsers.add(new TokenFormatDissector.NotImplementedTokenParser("$request_body_file", "nginx_parameter_not_intended_for_logging", FORMAT_STRING, -1)); // ------- // $request_completion // “OK” if a request has completed, or an empty string otherwise parsers.add(new TokenParser("$request_completion", "request.completion", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $request_filename // file path for the current request, based on the root or alias directives, and the request URI parsers.add(new TokenParser("$request_filename", "server.filename", "FILENAME", STRING_ONLY, TokenParser.FORMAT_STRING)); // ------- // $request_length // request length (including request line, header, and request body) (1.3.12, 1.2.7) parsers.add(new TokenParser("$request_length", "request.bytes", "BYTES", STRING_OR_LONG, TokenParser.FORMAT_CLF_NUMBER)); // ------- // $request_method // request method, usually “GET” or “POST” parsers.add(new TokenParser("$request_method", "request.firstline.method", "HTTP.METHOD", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $request_time // request processing time in seconds with a milliseconds resolution (1.3.9, 1.2.6); // time elapsed since the first bytes were read from the client parsers.add(new TokenParser("$request_time", "response.server.processing.time", "SECOND_MILLIS", STRING_ONLY, FORMAT_NUMBER_DECIMAL)); // ------- // $request_uri // full original request URI (with arguments) parsers.add(new TokenParser("$request_uri", "request.firstline.uri", "HTTP.URI", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $request_id // unique request identifier generated from 16 random bytes, in hexadecimal (1.11.0) parsers.add(new TokenParser("$request_id", "request.id", "STRING", STRING_ONLY, FORMAT_HEXNUMBER)); // ------- // $uri // current URI in request, normalized // The value of $uri may change during request processing, e.g. when doing internal redirects, or when using index files. parsers.add(new TokenParser("$uri", "request.firstline.uri.normalized", "HTTP.URI", STRING_ONLY, FORMAT_STRING)); // ------- // $document_uri // same as $uri parsers.add(new TokenParser("$document_uri", "request.firstline.uri.normalized", "HTTP.URI", STRING_ONLY, FORMAT_STRING)); // ------- // $scheme // request scheme, “http” or “https” parsers.add(new TokenParser("$scheme", "request.firstline.uri.protocol", "HTTP.PROTOCOL", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $sent_http_name // arbitrary response header field; the last part of a variable name is the field name converted to lower case with // dashes replaced by underscores parsers.add(new NamedTokenParser("\\$sent_http_([a-z0-9\\-_]*)", "response.header.", "HTTP.HEADER", STRING_ONLY, FORMAT_STRING)); // ------- // $sent_trailer_name // arbitrary field sent at the end of the response (1.13.2); the last part of a variable name is the field name // converted to lower case with dashes replaced by underscores parsers.add(new NamedTokenParser("\\$sent_trailer_([a-z0-9\\-_]*)", "response.trailer.", "HTTP.TRAILER", STRING_ONLY, FORMAT_STRING)); // ------- // $server_addr // an address of the server which accepted a request // Computing a value of this variable usually requires one system call. To avoid a system call, the listen // directives must specify addresses and use the bind parameter. parsers.add(new TokenParser("$server_addr", "connection.server.ip", "IP", STRING_OR_LONG, FORMAT_CLF_IP)); // ------- // $server_name // name of the server which accepted a request parsers.add(new TokenParser("$server_name", "connection.server.name", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ------- // $server_port // port of the server which accepted a request parsers.add(new TokenParser("$server_port", "connection.server.port", "PORT", STRING_OR_LONG, FORMAT_NUMBER)); // ------- // $server_protocol // request protocol, usually “HTTP/1.0” or “HTTP/1.1” parsers.add(new TokenParser("$server_protocol", "request.firstline.protocol", "HTTP.PROTOCOL_VERSION", STRING_OR_LONG, FORMAT_NO_SPACE_STRING)); // $session_time // session duration in seconds with a milliseconds resolution (1.11.4); parsers.add(new TokenParser("$session_time", "connection.session.time", "SECOND_MILLIS", STRING_ONLY, FORMAT_NUMBER_DECIMAL)); // ------- // $tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd, $tcpinfo_rcv_space // information about the client TCP connection; available on systems that support the TCP_INFO socket option // See http://linuxgazette.net/136/pfeiffer.html // tcpi_rtt and tcpi_rttvar are the Round Trip Time (RTT), and its smoothed mean deviation maximum measured in microseconds // $tcpinfo_rtt // $tcpinfo_rttvar parsers.add(new TokenParser("$tcpinfo_rtt", "connection.tcpinfo.rtt", "MICROSECONDS", STRING_OR_LONG, FORMAT_NUMBER, -1)); parsers.add(new TokenParser("$tcpinfo_rttvar", "connection.tcpinfo.rttvar", "MICROSECONDS", STRING_OR_LONG, FORMAT_NUMBER)); // $tcpinfo_snd_cwnd // tcpi_snd_cwnd is the sending congestion window. parsers.add(new TokenParser("$tcpinfo_snd_cwnd", "connection.tcpinfo.send.cwnd", "BYTES", STRING_OR_LONG, FORMAT_NUMBER)); // $tcpinfo_rcv_space parsers.add(new TokenParser("$tcpinfo_rcv_space", "connection.tcpinfo.receive.space", "BYTES", STRING_OR_LONG, FORMAT_NUMBER)); // // Some explicit type overrides. // // The '1' at the end indicates this is more important than the default TokenParser (which has an implicit 0). // parsers.add(new TokenParser("%{cookie}i", // "request.cookies", "HTTP.COOKIES", // STRING_ONLY, FORMAT_STRING, 1)); // parsers.add(new TokenParser("%{set-cookie}o", // "response.cookies", "HTTP.SETCOOKIES", // STRING_ONLY, FORMAT_STRING, 1)); // ------- // Fallback for all unknown variables that might appear parsers.add(new NamedTokenParser("\\$([a-z0-9\\-\\_]*)", "nginx.unknown.", "UNKNOWN_NGINX_VARIABLE", STRING_ONLY, FORMAT_NO_SPACE_STRING, -10) .setWarningMessageWhenUsed("Found unknown variable \"${}\" that was mapped to \"{}\". " + "It is assumed the values are text that cannot contain a whitespace.")); return parsers; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/GeoIPModule.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import java.util.ArrayList; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NO_SPACE_STRING; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STRING; // Implement the variables described here: // https://nginx.org/en/docs/http/ngx_http_geoip_module.html public class GeoIPModule implements NginxModule { private static final String PREFIX = "nginxmodule.geoip"; @Override public List getTokenParsers() { List parsers = new ArrayList<>(60); // $geoip_country_code // two-letter country code, for example, “RU”, “US”. parsers.add(new TokenParser("$geoip_country_code", PREFIX + ".country.code", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $geoip_country_code3 // three-letter country code, for example, “RUS”, “USA”. parsers.add(new TokenParser("$geoip_country_code3", PREFIX + ".country.code3", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $geoip_country_name // country name, for example, “Russian Federation”, “United States”. parsers.add(new TokenParser("$geoip_country_name", PREFIX + ".country.name", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_area_code telephone area code (US only). // This variable may contain outdated information since the corresponding database field is deprecated. parsers.add(new TokenParser("$geoip_area_code", PREFIX + ".area.code", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $geoip_city_continent_code // two-letter continent code, for example, “EU”, “NA”. parsers.add(new TokenParser("$geoip_city_continent_code", PREFIX + ".continent.code", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $geoip_city_country_code // two-letter country code, for example, “RU”, “US”. parsers.add(new TokenParser("$geoip_city_country_code", PREFIX + ".country.code", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $geoip_city_country_code3 // three-letter country code, for example, “RUS”, “USA”. parsers.add(new TokenParser("$geoip_city_country_code3", PREFIX + ".country.code3", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $geoip_city_country_name // country name, for example, “Russian Federation”, “United States”. parsers.add(new TokenParser("$geoip_city_country_name", PREFIX + ".country.name", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_dma_code // DMA region code in US (also known as “metro code”), according to the geotargeting in Google AdWords API. parsers.add(new TokenParser("$geoip_dma_code", PREFIX + ".dma.code", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_latitude // latitude. parsers.add(new TokenParser("$geoip_latitude", PREFIX + ".location.latitude", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_longitude // longitude. parsers.add(new TokenParser("$geoip_longitude", PREFIX + ".location.longitude", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_region // two-symbol country region code (region, territory, state, province, federal land and the like), for example, “48”, “DC”. parsers.add(new TokenParser("$geoip_region", PREFIX + ".region.code", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $geoip_region_name // country region name (region, territory, state, province, federal land and the like), for example, “Moscow City”, “District of Columbia”. parsers.add(new TokenParser("$geoip_region_name", PREFIX + ".region.name", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_city // city name, for example, “Moscow”, “Washington”. parsers.add(new TokenParser("$geoip_city", PREFIX + ".city", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_postal_code // postal code. parsers.add(new TokenParser("$geoip_postal_code", PREFIX + ".postal.code", "STRING", STRING_ONLY, FORMAT_STRING)); // $geoip_org // organization name, for example, “The University of Melbourne”. // TODO: Is is unclear is this is the ISP or the ASP organization parsers.add(new TokenParser("$geoip_org", PREFIX + ".organization", "STRING", STRING_ONLY, FORMAT_STRING)); return parsers; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/KubernetesIngressModule.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import java.util.ArrayList; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STRING; // // https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/log-format/ // public class KubernetesIngressModule implements NginxModule { private static final String PREFIX = "nginxmodule.kubernetes"; @Override public List getTokenParsers() { List parsers = new ArrayList<>(60); // $the_real_ip // the source IP address of the client parsers.add(new TokenParser("$the_real_ip", PREFIX + ".the_real_ip", "IP", STRING_ONLY, FORMAT_STRING)); // $proxy_upstream_name // name of the upstream. The format is upstream--- parsers.add(new TokenParser("$proxy_upstream_name", PREFIX + ".proxy_upstream_name", "STRING", STRING_ONLY, FORMAT_STRING)); // $req_id // the randomly generated ID of the request parsers.add(new TokenParser("$req_id", PREFIX + ".req_id", "STRING", STRING_ONLY, FORMAT_STRING)); // $namespace // namespace of the ingress parsers.add(new TokenParser("$namespace", PREFIX + ".namespace", "STRING", STRING_ONLY, FORMAT_STRING)); // $ingress_name // name of the ingress parsers.add(new TokenParser("$ingress_name", PREFIX + ".ingress_name", "STRING", STRING_ONLY, FORMAT_STRING)); // $service_name // name of the service parsers.add(new TokenParser("$service_name", PREFIX + ".service.name", "STRING", STRING_ONLY, FORMAT_STRING)); // $service_port // port of the service parsers.add(new TokenParser("$service_port", PREFIX + ".service.port", "PORT", STRING_ONLY, FORMAT_STRING)); return parsers; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/NginxModule.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import java.util.Collections; import java.util.List; public interface NginxModule { List getTokenParsers(); default List getDissectors() { return Collections.emptyList(); // By default no extra dissectors } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/SslModule.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import java.util.ArrayList; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NO_SPACE_STRING; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STRING; // Implement the tokens described here: // https://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables // https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#variables // https://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html#variables public class SslModule implements NginxModule { private static final String PREFIX = "nginxmodule.ssl"; @Override public List getTokenParsers() { List parsers = new ArrayList<>(60); // $ssl_cipher // returns the string of ciphers used for an established SSL connection; parsers.add(new TokenParser("$ssl_cipher", PREFIX + ".cipher", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_ciphers // returns the list of ciphers supported by the client (1.11.7). // Known ciphers are listed by names, unknown are shown in hexadecimal, // for example: AES128-SHA:AES256-SHA:0x00ff parsers.add(new TokenParser("$ssl_ciphers", PREFIX + ".client.ciphers", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_client_escaped_cert // returns the client certificate in the PEM format (urlencoded) for an established SSL connection (1.13.5); parsers.add(new TokenParser("$ssl_client_escaped_cert", PREFIX + ".client.cert", "PEM_CERT_URLENCODED", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $ssl_client_cert --> IS DEPRECATED USE $ssl_client_escaped_cert // returns the client certificate in the PEM format for an established SSL connection, // with each line except the first prepended with the tab character; // this is intended for the use in the proxy_set_header directive; // The variable is deprecated, the $ssl_client_escaped_cert variable should be used instead. parsers.add(new TokenParser("$ssl_client_cert", PREFIX + ".client.cert", "PEM_CERT", STRING_ONLY, FORMAT_STRING)); // $ssl_client_raw_cert // returns the client certificate in the PEM format for an established SSL connection; parsers.add(new TokenParser("$ssl_client_raw_cert", PREFIX + ".client.cert", "PEM_CERT_RAW", STRING_ONLY, FORMAT_STRING)); // $ssl_client_fingerprint // returns the SHA1 fingerprint of the client certificate for an established SSL connection (1.7.1); parsers.add(new TokenParser("$ssl_client_fingerprint", PREFIX + ".client.cert.fingerprint", "SHA1", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $ssl_client_i_dn // returns the “issuer DN” string of the client certificate for an established SSL connection according to RFC 2253 (1.11.6); parsers.add(new TokenParser("$ssl_client_i_dn", PREFIX + ".client.cert.issuer_dn", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_client_i_dn_legacy // returns the “issuer DN” string of the client certificate for an established SSL connection; // Prior to version 1.11.6, the variable name was $ssl_client_i_dn. parsers.add(new TokenParser("$ssl_client_i_dn_legacy", PREFIX + ".client.cert.issuer_dn.legacy", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_client_s_dn // returns the “subject DN” string of the client certificate for an established SSL connection according to RFC 2253 (1.11.6); parsers.add(new TokenParser("$ssl_client_s_dn", PREFIX + ".client.cert.subject_dn", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_client_s_dn_legacy // returns the “subject DN” string of the client certificate for an established SSL connection; // Prior to version 1.11.6, the variable name was $ssl_client_s_dn. parsers.add(new TokenParser("$ssl_client_s_dn_legacy", PREFIX + ".client.cert.subject_dn.legacy", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_client_serial // returns the serial number of the client certificate for an established SSL connection; parsers.add(new TokenParser("$ssl_client_serial", PREFIX + ".client.cert.serial", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_client_v_end // returns the end date of the client certificate (1.11.7); parsers.add(new TokenParser("$ssl_client_v_end", PREFIX + ".client.cert.end_date", "STRING", // TODO: What is the format of this date? STRING_ONLY, FORMAT_STRING)); // $ssl_client_v_remain // returns the number of days until the client certificate expires (1.11.7); parsers.add(new TokenParser("$ssl_client_v_remain", PREFIX + ".client.cert.remain_days", "STRING", // TODO: What is the format of this? STRING_ONLY, FORMAT_STRING)); // $ssl_client_v_start // returns the start date of the client certificate (1.11.7); parsers.add(new TokenParser("$ssl_client_v_start", PREFIX + ".client.cert.start_date", "STRING", // TODO: What is the format of this date? STRING_ONLY, FORMAT_STRING)); // $ssl_client_verify // returns the result of client certificate verification: // “SUCCESS”, “FAILED:reason”, and “NONE” if a certificate was not present; // Prior to version 1.11.7, the “FAILED” result did not contain the reason string. parsers.add(new TokenParser("$ssl_client_verify", PREFIX + ".client.cert.verify", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_curves // returns the list of curves supported by the client (1.11.7). // Known curves are listed by names, unknown are shown in hexadecimal, // for example: 0x001d:prime256v1:secp521r1:secp384r1 // The variable is supported only when using OpenSSL version 1.0.2 or higher. // With older versions, the variable value will be an empty string. The variable is available only for new sessions. parsers.add(new TokenParser("$ssl_curves", PREFIX + ".client.curves", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_early_data // returns “1” if TLS 1.3 early data is used and the handshake is not complete, otherwise “” (1.15.3). parsers.add(new TokenParser("$ssl_early_data", PREFIX + ".early_data", "STRING", STRING_ONLY, "1?")); // $ssl_protocol // returns the protocol of an established SSL connection; parsers.add(new TokenParser("$ssl_protocol", PREFIX + ".protocol", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_server_name // returns the server name requested through SNI (1.7.0); parsers.add(new TokenParser("$ssl_server_name", PREFIX + ".server_name", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_session_id // returns the session identifier of an established SSL connection; parsers.add(new TokenParser("$ssl_session_id", PREFIX + ".session.id", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_session_reused // returns “r” if an SSL session was reused, or “.” otherwise (1.5.11). parsers.add(new TokenParser("$ssl_session_reused", PREFIX + ".session.reused", "STRING", STRING_ONLY, "(r|.)")); // $ssl_preread_protocol // the highest SSL protocol version supported by the client (1.15.2) parsers.add(new TokenParser("$ssl_preread_protocol", PREFIX + ".preread.protocol", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_preread_server_name // server name requested through SNI parsers.add(new TokenParser("$ssl_preread_server_name", PREFIX + ".preread.server_name", "STRING", STRING_ONLY, FORMAT_STRING)); // $ssl_preread_alpn_protocols // list of protocols advertised by the client through ALPN (1.13.10). // The values are separated by commas. parsers.add(new TokenParser("$ssl_preread_alpn_protocols", PREFIX + ".preread.alpn_protocols", "STRING", STRING_ONLY, FORMAT_STRING)); return parsers; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/UpstreamListDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import static nl.basjes.parse.core.Casts.NO_CASTS; // Implement the tokens described here: // https://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables // $upstream_addr // keeps the IP address and port, or the path to the UNIX-domain socket of the upstream server. // If several servers were contacted during request processing, their addresses are separated by commas, // e.g. “192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock”. // // If an internal redirect from one server group to another happens, initiated by “X-Accel-Redirect” // or error_page, then the server addresses from different groups are separated by colons, // e.g. “192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80”. // // If a server cannot be selected, the variable keeps the name of the server group. // This dissector tries to pick apart this list format. public class UpstreamListDissector extends Dissector { private static final String OUTPUT_ORIGINAL_NAME = ".value"; private static final String OUTPUT_REDIRECTED_NAME = ".redirected"; private String inputType; private String outputOriginalType; private EnumSet outputOriginalCasts; private String outputRedirectedType; private EnumSet outputRedirectedCasts; public UpstreamListDissector() { inputType = null; outputOriginalType = null; outputOriginalCasts = null; outputRedirectedType = null; outputRedirectedCasts = null; } public UpstreamListDissector(String inputType, String outputOriginalType, EnumSet outputOriginalCasts, String outputRedirectedType, EnumSet outputRedirectedCasts) { this.inputType = inputType; this.outputOriginalType = outputOriginalType; this.outputOriginalCasts = outputOriginalCasts; this.outputRedirectedType = outputRedirectedType; this.outputRedirectedCasts = outputRedirectedCasts; } @Override public void dissect(Parsable parsable, String inputname) throws DissectionFailure { final ParsedField field = parsable.getParsableField(inputType, inputname); String fieldValue = field.getValue().getString(); if (fieldValue == null || fieldValue.isEmpty()) { return; // Nothing to do. } String[] servers = fieldValue.split(", "); int serverNr = 0; for (String server: servers) { String[] parts = server.split(": "); if (parts.length == 1) { parsable.addDissection(inputname, outputOriginalType, serverNr + OUTPUT_ORIGINAL_NAME, parts[0].trim()); parsable.addDissection(inputname, outputRedirectedType, serverNr + OUTPUT_REDIRECTED_NAME, parts[0].trim()); } else { parsable.addDissection(inputname, outputOriginalType, serverNr + OUTPUT_ORIGINAL_NAME, parts[0].trim()); parsable.addDissection(inputname, outputRedirectedType, serverNr + OUTPUT_REDIRECTED_NAME, parts[1].trim()); } serverNr++; } } @Override public String getInputType() { return inputType; } @Override public List getPossibleOutput() { List result = new ArrayList<>(); for (int i = 0; i < 32; i++){ result.add(outputOriginalType + ":" + i + OUTPUT_ORIGINAL_NAME); result.add(outputRedirectedType + ":" + i + OUTPUT_REDIRECTED_NAME); } return result; } @Override public EnumSet prepareForDissect(String inputname, String outputname) { String name = extractFieldName(inputname, outputname); if (name.endsWith(OUTPUT_ORIGINAL_NAME)) { return outputOriginalCasts; } if (name.endsWith(OUTPUT_REDIRECTED_NAME)) { return outputRedirectedCasts; } return NO_CASTS; } @Override protected void initializeNewInstance(Dissector newInstance) throws InvalidDissectorException { if (!(newInstance instanceof UpstreamListDissector)) { throw new InvalidDissectorException( "Called UpstreamListDissector::initializeNewInstance with a dissector of class " + newInstance.getClass().getCanonicalName()); } UpstreamListDissector dissector = (UpstreamListDissector)newInstance; dissector.inputType = inputType; dissector.outputOriginalType = outputOriginalType; dissector.outputOriginalCasts = outputOriginalCasts; dissector.outputRedirectedType = outputRedirectedType; dissector.outputRedirectedCasts = outputRedirectedCasts; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/UpstreamModule.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.httpdlog.dissectors.tokenformat.NamedTokenParser; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import java.util.ArrayList; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; import static nl.basjes.parse.core.Casts.STRING_OR_LONG_OR_DOUBLE; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NO_SPACE_STRING; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NUMBER; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NUMBER_DECIMAL; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STRING; // Implement the tokens described here: // https://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables // https://nginx.org/en/docs/stream/ngx_stream_upstream_module.html#variables public class UpstreamModule implements NginxModule { private static final String PREFIX = "nginxmodule.upstream"; private String upstreamListOf(String regex) { return regex + "(?: *, *" + regex + "(?: *: *" + regex + ")?)*"; } private String optionalUpstreamListOf(String regex) { return "(?:" + upstreamListOf(regex) + "|-)"; } @Override public List getTokenParsers() { List parsers = new ArrayList<>(60); // NOTE: All values are really optional (so they may also be a '-') because the required 'upstream' module // is not guaranteed to be running. // $upstream_addr // keeps the IP address and port, or the path to the UNIX-domain socket of the upstream server. // If several servers were contacted during request processing, their addresses are separated by commas, // e.g. “192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock”. // // If an internal redirect from one server group to another happens, initiated by “X-Accel-Redirect” // or error_page, then the server addresses from different groups are separated by colons, // e.g. “192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80”. // // If a server cannot be selected, the variable keeps the name of the server group. parsers.add(new TokenParser("$upstream_addr", PREFIX + ".addr", "UPSTREAM_ADDR_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NO_SPACE_STRING))); // $upstream_bytes_received // number of bytes received from an upstream server. // Values from several connections are separated by commas and colons like addresses // in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_bytes_received", PREFIX + ".bytes.received", "UPSTREAM_BYTES_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER))); // $upstream_bytes_sent // number of bytes sent to an upstream server. // Values from several connections are separated by commas and colons like addresses // in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_bytes_sent", PREFIX + ".bytes.sent", "UPSTREAM_BYTES_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER))); // $upstream_cache_status // keeps the status of accessing a response cache. // The status can be either “MISS”, “BYPASS”, “EXPIRED”, “STALE”, “UPDATING”, “REVALIDATED”, or “HIT”. parsers.add(new TokenParser("$upstream_cache_status", PREFIX + ".cache.status", "UPSTREAM_CACHE_STATUS", STRING_ONLY, "(?:MISS|BYPASS|EXPIRED|STALE|UPDATING|REVALIDATED|HIT)")); // $upstream_connect_time // keeps time spent on establishing a connection with the upstream server (1.9.1); // the time is kept in seconds with millisecond resolution. In case of SSL, includes time spent on handshake. // Times of several connections are separated by commas and colons like addresses in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_connect_time", PREFIX + ".connect.time", "UPSTREAM_SECOND_MILLIS_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER_DECIMAL))); // $upstream_cookie_name // cookie with the specified name sent by the upstream server in the “Set-Cookie” response header field (1.7.1). // Only the cookies from the response of the last server are saved. parsers.add(new NamedTokenParser("\\$upstream_cookie_([a-z0-9\\-_]*)", PREFIX + ".response.cookies.", "HTTP.COOKIE", STRING_ONLY, FORMAT_STRING)); // $upstream_header_time // keeps time spent on receiving the response header from the upstream server (1.7.10); // the time is kept in seconds with millisecond resolution. // Times of several responses are separated by commas and colons like addresses in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_header_time", PREFIX + ".header.time", "UPSTREAM_SECOND_MILLIS_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER_DECIMAL))); // $upstream_http_name // keep server response header fields. For example, the “Server” response header field is available through // the $upstream_http_server variable. The rules of converting header field names to variable names are // the same as for the variables that start with the “$http_” prefix. // Only the header fields from the response of the last server are saved. parsers.add(new NamedTokenParser("\\$upstream_http_([a-z0-9\\-_]*)", PREFIX + ".header.", "HTTP.HEADER", STRING_ONLY, FORMAT_STRING)); // $upstream_queue_time // keeps time the request spent in the upstream queue (1.13.9); // the time is kept in seconds with millisecond resolution. // Times of several responses are separated by commas and colons like addresses in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_queue_time", PREFIX + ".queue.time", "UPSTREAM_SECOND_MILLIS_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER_DECIMAL))); // $upstream_response_length // keeps the length of the response obtained from the upstream server (0.7.27); // the length is kept in bytes. // Lengths of several responses are separated by commas and colons like addresses in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_response_length", PREFIX + ".response.length", "UPSTREAM_BYTES_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER))); // $upstream_response_time // keeps time spent on receiving the response from the upstream server; // the time is kept in seconds with millisecond resolution. // Times of several responses are separated by commas and colons like addresses in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_response_time", PREFIX + ".response.time", "UPSTREAM_SECOND_MILLIS_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER_DECIMAL))); // $upstream_status // keeps status code of the response obtained from the upstream server. // Status codes of several responses are separated by commas and colons like addresses in the $upstream_addr // variable. If a server cannot be selected, the variable keeps the 502 (Bad Gateway) status code. parsers.add(new TokenParser("$upstream_status", PREFIX + ".status", "UPSTREAM_STATUS_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NO_SPACE_STRING))); // $upstream_trailer_name // keeps fields from the end of the response obtained from the upstream server (1.13.10). parsers.add(new NamedTokenParser("\\$upstream_trailer_([a-z0-9\\-_]*)", PREFIX + ".trailer.", "HTTP.TRAILER", STRING_ONLY, FORMAT_STRING)); // $upstream_first_byte_time // time to receive the first byte of data (1.11.4); the time is kept in seconds with millisecond resolution. // Times of several connections are separated by commas like addresses in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_first_byte_time", PREFIX + ".first_byte.time", "UPSTREAM_SECOND_MILLIS_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER_DECIMAL))); // $upstream_session_time // session duration in seconds with millisecond resolution (1.11.4). // Times of several connections are separated by commas like addresses in the $upstream_addr variable. parsers.add(new TokenParser("$upstream_session_time", PREFIX + ".session.time", "UPSTREAM_SECOND_MILLIS_LIST", STRING_ONLY, optionalUpstreamListOf(FORMAT_NUMBER_DECIMAL))); return parsers; } @Override public List getDissectors() { List dissectors = new ArrayList<>(); dissectors.add(new UpstreamListDissector( "UPSTREAM_ADDR_LIST", "UPSTREAM_ADDR", STRING_ONLY, "UPSTREAM_ADDR", STRING_ONLY)); dissectors.add(new UpstreamListDissector( "UPSTREAM_BYTES_LIST", "BYTES", STRING_OR_LONG, "BYTES", STRING_OR_LONG)); dissectors.add(new UpstreamListDissector( "UPSTREAM_SECOND_MILLIS_LIST", "SECOND_MILLIS", STRING_OR_LONG_OR_DOUBLE, "SECOND_MILLIS", STRING_OR_LONG_OR_DOUBLE)); dissectors.add(new UpstreamListDissector( "UPSTREAM_STATUS_LIST", "UPSTREAM_STATUS", STRING_ONLY, "UPSTREAM_STATUS", STRING_ONLY)); return dissectors; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/nginxmodules/VariousModule.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.nginxmodules; import nl.basjes.parse.httpdlog.dissectors.tokenformat.NamedTokenParser; import nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser; import java.util.ArrayList; import java.util.List; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NO_SPACE_STRING; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_NUMBER_OPTIONAL_DECIMAL; import static nl.basjes.parse.httpdlog.dissectors.tokenformat.TokenParser.FORMAT_STRING; // Many nginx modules only have a small number of variables: public class VariousModule implements NginxModule { private static final String PREFIX = "nginxmodule"; @Override public List getTokenParsers() { List parsers = new ArrayList<>(60); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_secure_link_module.html#var_secure_link // $secure_link // The status of a link check. The specific value depends on the selected operation mode. parsers.add(new TokenParser("$secure_link", PREFIX + ".secure_link.status", "STRING", STRING_ONLY, FORMAT_STRING)); // $secure_link_expires // The lifetime of a link passed in a request; intended to be used only in the secure_link_md5 directive. // --- NOT FOR LOGGING --- // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_session_log_module.html#var_session_log_id // $session_log_id // current session ID; parsers.add(new TokenParser("$session_log_id", PREFIX + ".session_log.id", "STRING", STRING_ONLY, FORMAT_STRING)); // NOT FOR LOGGING $ session_log_binary_id current session ID in binary form (16 bytes). // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_slice_module.html#var_slice_range // $slice_range // the current slice range in HTTP byte range format, for example, bytes=0-1048575. parsers.add(new TokenParser("$slice_range", PREFIX + ".slice_range", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_proxy_module.html#var_proxy_add_x_forwarded_for // $proxy_host // name and port of a proxied server as specified in the proxy_pass directive; parsers.add(new TokenParser("$proxy_host", PREFIX + ".proxy.host", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $proxy_port // port of a proxied server as specified in the proxy_pass directive, or the protocol’s default port; parsers.add(new TokenParser("$proxy_port", PREFIX + ".proxy.port", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // $proxy_add_x_forwarded_for // the “X-Forwarded-For” client request header field with the $remote_addr variable appended to it, separated by a comma. // If the “X-Forwarded-For” field is not present in the client request header, // the $proxy_add_x_forwarded_for variable is equal to the $remote_addr variable. parsers.add(new TokenParser("$proxy_add_x_forwarded_for", PREFIX + ".proxy.add_x_forwarded_for", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_userid_module.html#var_uid_got // $uid_got // The cookie name and received client identifier. parsers.add(new TokenParser("$uid_got", PREFIX + ".userid.uid_got", "STRING", STRING_ONLY, FORMAT_STRING)); // $uid_reset // If the variable is set to a non-empty string that is not “0”, the client identifiers are reset. // The special value “log” additionally leads to the output of messages about the reset identifiers to the error_log. parsers.add(new TokenParser("$uid_reset", PREFIX + ".userid.uid_reset", "STRING", STRING_ONLY, FORMAT_STRING)); // $uid_set // The cookie name and sent client identifier. parsers.add(new TokenParser("$uid_set", PREFIX + ".userid.uid_set", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_browser_module.html#var_msie // $modern_browser // equals the value set by the modern_browser_value directive, if a browser was identified as modern; parsers.add(new TokenParser("$modern_browser", PREFIX + ".browser.modern", "STRING", STRING_ONLY, FORMAT_STRING)); // $ancient_browser // equals the value set by the ancient_browser_value directive, if a browser was identified as ancient; parsers.add(new TokenParser("$ancient_browser", PREFIX + ".browser.ancient", "STRING", STRING_ONLY, FORMAT_STRING)); // $msie // equals “1” if a browser was identified as MSIE of any version. parsers.add(new TokenParser("$msie", PREFIX + ".browser.msie", "STRING", STRING_ONLY, FORMAT_NO_SPACE_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_stub_status_module.html#var_connections_active // $connections_active // The current number of active client connections including Waiting connections. parsers.add(new TokenParser("$connections_active", PREFIX + ".stub_status.connections.active", "STRING", STRING_ONLY, FORMAT_STRING)); // $connections_reading // The current number of connections where nginx is reading the request header. parsers.add(new TokenParser("$connections_reading", PREFIX + ".stub_status.connections.reading", "STRING", STRING_ONLY, FORMAT_STRING)); // $connections_writing // The current number of connections where nginx is writing the response back to the client. parsers.add(new TokenParser("$connections_writing", PREFIX + ".stub_status.connections.writing", "STRING", STRING_ONLY, FORMAT_STRING)); // $connections_waiting // The current number of idle client connections waiting for a request. parsers.add(new TokenParser("$connections_waiting", PREFIX + ".stub_status.connections.waiting", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_ssi_module.html#var_date_gmt // NOTE: These two are STRING because the actual format is unknown (it is configurable) // $date_local // current time in the local time zone. The format is set by the config command with the timefmt parameter. parsers.add(new TokenParser("$date_local", PREFIX + ".date.local", "STRING", STRING_ONLY, FORMAT_STRING)); // $date_gmt // current time in GMT. The format is set by the config command with the timefmt parameter. parsers.add(new TokenParser("$date_gmt", PREFIX + ".date.gmt", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // $fastcgi_script_name // request URI or, if a URI ends with a slash, request URI with an index file name configured by the fastcgi_index // directive appended to it. parsers.add(new TokenParser("$fastcgi_script_name", PREFIX + ".fastcgi.script_name", "STRING", STRING_ONLY, FORMAT_STRING)); // $fastcgi_path_info // the value of the second capture set by the fastcgi_split_path_info directive. This variable can be used to set the PATH_INFO parameter. parsers.add(new TokenParser("$fastcgi_path_info", PREFIX + ".fastcgi.path_info", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_gzip_module.html#var_gzip_ratio // $gzip_ratio // achieved compression ratio, computed as the ratio between the original and compressed response sizes. parsers.add(new TokenParser("$gzip_ratio", PREFIX + ".gzip.ratio", "STRING", STRING_ONLY, FORMAT_NUMBER_OPTIONAL_DECIMAL)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_spdy_module.html#var_spdy // $spdy // SPDY protocol version for SPDY connections, or an empty string otherwise; parsers.add(new TokenParser("$spdy", PREFIX + ".spdy.version", "STRING", STRING_ONLY, FORMAT_STRING)); // $spdy_request_priority // request priority for SPDY connections, or an empty string otherwise. parsers.add(new TokenParser("$spdy_request_priority", PREFIX + ".spdy.request_priority", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_v2_module.html#var_http2 // $http2 // negotiated protocol identifier: “h2” for HTTP/2 over TLS, “h2c” for HTTP/2 over cleartext TCP, or an empty string otherwise. parsers.add(new TokenParser("$http2", PREFIX + ".http2.negotiated_protocol", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_referer_module.html#var_invalid_referer // $invalid_referer // Empty string, if the “Referer” request header field value is considered valid, otherwise “1”. parsers.add(new TokenParser("$invalid_referer", PREFIX + ".referer.invalid", "STRING", STRING_ONLY, "1?")); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_auth_jwt_module.html#var_jwt_claim_ // $jwt_header_name // returns the value of a specified JOSE header parsers.add(new NamedTokenParser("\\$jwt_header_([a-z0-9\\-_]*)", PREFIX + ".jwt.header.", "STRING", STRING_ONLY, FORMAT_STRING)); // $jwt_claim_name // returns the value of a specified JWT claim parsers.add(new NamedTokenParser("\\$jwt_claim_([a-z0-9\\-_]*)", PREFIX + ".jwt.claim.", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_memcached_module.html#var_memcached_key // $memcached_key // Defines a key for obtaining response from a memcached server. parsers.add(new TokenParser("$memcached_key", PREFIX + ".memcached.key", "STRING", STRING_ONLY, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- // https://nginx.org/en/docs/http/ngx_http_realip_module.html#var_realip_remote_addr // https://nginx.org/en/docs/stream/ngx_stream_realip_module.html#var_realip_remote_addr // $realip_remote_addr // keeps the original client address parsers.add(new TokenParser("$realip_remote_addr", PREFIX + ".realip.remote_addr", "IP", STRING_ONLY, FORMAT_STRING)); // $realip_remote_port // keeps the original client port parsers.add(new TokenParser("$realip_remote_port", PREFIX + ".realip.remote_port", "PORT", STRING_OR_LONG, FORMAT_STRING)); // ----------------------------------------------------------------------------------------------------- return parsers; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/tokenformat/NamedTokenParser.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.tokenformat; import nl.basjes.parse.core.Casts; import java.util.EnumSet; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This is a TokenParser where we expect to get the NAME of the field as a group in the regular expression. */ public class NamedTokenParser extends TokenParser { private final Pattern pattern; // -------------------------------------------- public NamedTokenParser( final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex) { this(nLogFormatToken, nValueName, nValueType, nCasts, nRegex, 0); } public NamedTokenParser( final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex, final int prio) { super(nLogFormatToken, nValueName, nValueType, nCasts, nRegex, prio); // Compile the regular expression pattern = Pattern.compile(getLogFormatToken()); } // -------------------------------------------- @Override public Token getNextToken(final String logFormat, final int startOffset) { final Matcher matcher = pattern.matcher(logFormat.substring(startOffset)); if (!matcher.find()) { return null; } String fieldName = ""; if (matcher.groupCount() > 0) { // Retrieve the name fieldName = matcher.group(1); } // Retrieve indices of matching string final int start = matcher.start(); final int end = matcher.end(); // the end is index of the last matching character + 1 Token token = new Token( getRegex(), startOffset + start, end - start, getPrio()); for (TokenOutputField tokenOutputField: getOutputFields()) { token.addOutputField( tokenOutputField.getType(), tokenOutputField.getName() + fieldName, tokenOutputField.getCasts()); } if (warningMessageWhenUsed != null) { token.setWarningMessageWhenUsed(warningMessageWhenUsed.replaceFirst("\\{}", fieldName)); } return token; } // -------------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/tokenformat/ParameterizedTokenParser.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.tokenformat; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import org.apache.commons.codec.binary.Hex; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This is a TokenParser where we expect to get the constructor parameter for the provided dissector as a group in * the regular expression. As a consequence the type is a generated string to match THIS dissector instance. */ public class ParameterizedTokenParser extends TokenParser { private final Pattern pattern; // -------------------------------------------- public ParameterizedTokenParser( final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex, final int prio, final Dissector customDissector) { super(nLogFormatToken, nValueName, nValueType, nCasts, nRegex, prio, customDissector); // Compile the regular expression pattern = Pattern.compile(getLogFormatToken()); } @Override public TokenParser addOutputField(String type, String name, EnumSet casts) { if (getOutputFields().isEmpty()) { return super.addOutputField(type, name, casts); } throw new UnsupportedOperationException("A ParameterizedTokenParser only supports ONE outputfield."); } @Override public TokenParser addOutputFields(List outputFields) { if (getOutputFields().isEmpty()) { return super.addOutputFields(outputFields); } throw new UnsupportedOperationException("A ParameterizedTokenParser only supports ONE outputfield."); } // -------------------------------------------- @Override public Token getNextToken(final String logFormat, final int startOffset) { final Matcher matcher = pattern.matcher(logFormat.substring(startOffset)); if (!matcher.find()) { return null; } String fieldName = ""; if (matcher.groupCount() > 0) { // Retrieve the name fieldName = matcher.group(1); } // Retrieve indices of matching string final int start = matcher.start(); final int end = matcher.end(); // the end is index of the last matching character + 1 Token token = new Token( getRegex(), startOffset + start, end - start, getPrio()); for (TokenOutputField tokenOutputField: getOutputFields()) { String fieldType = tokenParameterToTypeName(fieldName); token.addOutputField( tokenParameterToTypeName(fieldName), tokenOutputField.getName(), tokenOutputField.getCasts()); addCustomDissector(token, fieldType, fieldName); } if (warningMessageWhenUsed != null) { token.setWarningMessageWhenUsed(warningMessageWhenUsed.replaceFirst("\\{}", fieldName)); } return token; } // -------------------------------------------- String tokenParameterToTypeName(String parameter) { return ( getOutputFields().get(0).getType() + parameter.replaceAll("[^A-Za-z0-9]", "") + "_" + stringHashAsHexString(parameter) ).toUpperCase(Locale.ENGLISH); } private String stringHashAsHexString(String input) { String result = ""; try { MessageDigest md = MessageDigest.getInstance("MD5"); result = Hex.encodeHexString(md.digest(input.getBytes())); } catch (NoSuchAlgorithmException e) { // Shouldn't happen } return result; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/tokenformat/Token.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.tokenformat; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.Set; public class Token implements Serializable { private static final Logger LOG = LoggerFactory.getLogger(Token.class); private final List outputFields = new ArrayList<>(); private final String regex; private final int startPos; private final int length; private final int prio; protected String warningMessageWhenUsed = null; // In some cases a token needs a custom dissector. private Dissector customDissector = null; public Token( final String nRegex, final int nStartPos, final int nLength, final int nPrio) { regex = nRegex; startPos = nStartPos; length = nLength; prio = nPrio; } public Token addOutputField(String type, String name, EnumSet casts) { outputFields.add(new TokenOutputField(type, name, casts)); return this; } public Token addOutputFields(List nOutputFields) { this.outputFields.addAll(nOutputFields); return this; } public List getOutputFields() { return outputFields; } public boolean canProduceADesiredFieldName(Set desiredNames) { for (TokenOutputField tokenOutputField: outputFields) { if (desiredNames.contains(tokenOutputField.getName())) { return true; } } return false; } public void setCustomDissector(Dissector dissector) { customDissector = dissector; } public Dissector getCustomDissector() { return customDissector; } public String getRegex() { return regex; } public int getStartPos() { return startPos; } public int getLength() { return length; } public int getPrio() { return prio; } public void setWarningMessageWhenUsed(String message) { warningMessageWhenUsed = message; } public void tokenWasUsed() { if (warningMessageWhenUsed != null) { LOG.warn("------------------------------------------------------------------------"); LOG.warn(warningMessageWhenUsed, outputFields); LOG.warn("------------------------------------------------------------------------"); } } // This is used by your favorite debugger. @Override public String toString() { return "{" + outputFields + " (" + startPos + "+" + length + ");Prio=" + prio + "}"; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/tokenformat/TokenFormatDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.tokenformat; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.ParsedField; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import static nl.basjes.parse.core.Casts.STRING_ONLY; @SuppressWarnings({ "PMD.LongVariable", // I like my variable names this way "PMD.CyclomaticComplexity", "PMD.OnlyOneReturn", "PMD.BeanMembersShouldSerialize", // No beans here "PMD.DataflowAnomalyAnalysis" // Results in a lot of mostly useless messages. }) public abstract class TokenFormatDissector extends Dissector { private static final Logger LOG = LoggerFactory.getLogger(TokenFormatDissector.class); private String logFormat = null; private ArrayList logFormatUsedTokens = null; // Using ArrayList because it is Serializable private String logFormatRegEx = null; private Pattern logFormatPattern = null; private boolean isUsable = false; private List logFormatTokens; private List outputTypes; // -------------------------------------------- public static class FixedStringTokenParser extends TokenParser { public FixedStringTokenParser(final String nLogFormatToken, final String nRegEx) { super(nLogFormatToken, nRegEx, 0); } @Override public Token getNextToken(String logFormat, int startOffset) { final int pos = logFormat.indexOf(getLogFormatToken(), startOffset); if (pos == -1) { return null; } return new FixedStringToken( getRegex(), pos, getLogFormatToken().length(), 0) .addOutputFields(getOutputFields()); } } public static class FixedStringToken extends Token { public FixedStringToken(String nRegex, int nStartPos, int nLength, int nPrio) { super(nRegex, nStartPos, nLength, nPrio); } } // -------------------------------------------- public static class NotImplementedTokenParser extends TokenParser { public NotImplementedTokenParser(final String nLogFormatToken, final String fieldPrefix, int nPrio) { this(nLogFormatToken, fieldPrefix, ".*", nPrio); } public NotImplementedTokenParser(final String nLogFormatToken, final String fieldPrefix, final String regEx, int nPrio) { super(nLogFormatToken, fieldPrefix + "_" + nLogFormatToken.toLowerCase(Locale.ENGLISH).replaceAll("[^a-z0-9_]", "_"), "NOT_IMPLEMENTED", STRING_ONLY, regEx, nPrio); } } public TokenFormatDissector(final String logFormat) { setLogFormat(logFormat); } public TokenFormatDissector() { } @Override public boolean initializeFromSettingsParameter(String settings) { setLogFormat(logFormat); return true; // Everything went right } @Override protected void initializeNewInstance(Dissector newInstance) { if (newInstance instanceof TokenFormatDissector) { ((TokenFormatDissector)newInstance).setLogFormat(logFormat); } else { LOG.error("============================== WTF == {}", newInstance.getClass().getCanonicalName()); } } public void setLogFormat(final String logformat) { this.logFormat = logformat; // Now we disassemble the format into parts logFormatTokens = parseTokenLogFileDefinition(this.logFormat); outputTypes = new ArrayList<>(); for (final Token token : logFormatTokens) { if (token instanceof FixedStringToken) { continue; } List outputFields = token.getOutputFields(); if (!outputFields.isEmpty()) { for (TokenOutputField tokenOutputField: outputFields) { outputTypes.add(tokenOutputField.getType() + ':' + tokenOutputField.getName()); } } } } public String getLogFormat() { return logFormat; } @SuppressWarnings("unused") // Useful for debugging purposes public String getLogFormatRegEx() { return logFormatRegEx; } // -------------------------------------------- private final Set requestedFields = new HashSet<>(16); @Override public EnumSet prepareForDissect(final String inputName, final String outputName) { requestedFields.add(outputName); for (Token token: logFormatTokens) { for (TokenOutputField tokenOutputField: token.getOutputFields()) { if (outputName.equals(tokenOutputField.getName())) { tokenOutputField.wasUsed(); return tokenOutputField.getCasts(); } } } return STRING_ONLY; } // -------------------------------------------- @Override public void prepareForRun() { // At this point we have all the tokens and now we construct the // complete regex and the list to use when extracting // We build the regexp so that it only extracts the needed parts. // Allocated buffer is a bit bigger than needed final StringBuilder regex = new StringBuilder(logFormatTokens.size() * 16); logFormatUsedTokens = new ArrayList<>(); regex.append('^'); // Link to start of the line for (final Token token : logFormatTokens) { token.tokenWasUsed(); if (token instanceof FixedStringToken) { // Only insert the fixed part regex.append(Pattern.quote(token.getRegex())); } else if (token.canProduceADesiredFieldName(requestedFields)) { logFormatUsedTokens.add(token); regex.append("(").append(token.getRegex()).append(")"); } else { regex.append("(?:").append(token.getRegex()).append(")"); } } regex.append('$'); // Link to end of the line logFormatRegEx = regex.toString(); LOG.debug("Source logformat : {}", logFormat); LOG.debug("Used regex : {}", logFormatRegEx); // Now we compile this expression ONLY ONCE! logFormatPattern = Pattern.compile(logFormatRegEx); isUsable = true; // Ready! } // -------------------------------------------- @Override public void setInputType(String newInputType) { this.inputType = newInputType; } private String inputType = null; @Override public String getInputType() { return inputType; } @Override public List getPossibleOutput() { return outputTypes; } /** * * @param tokenName Name of the token that was found * @param value The actual value as it is present in the logline * @return The cleaned/decoded/interpreted version of the value. */ public abstract String decodeExtractedValue(String tokenName, String value); @Override public void dissect(final Parsable parsable, final String inputname) throws DissectionFailure { if (!isUsable) { throw new DissectionFailure("Dissector in unusable state"); } final ParsedField line = parsable.getParsableField(inputType, inputname); // Now we create a matcher for this line final Matcher matcher = logFormatPattern.matcher(line.getValue().getString()); // Is it all as expected? final boolean matches = matcher.find(); if (matches) { for (int i = 1; i <= matcher.groupCount(); i++) { String matchedStr = matcher.group(i); Token token = logFormatUsedTokens.get(i-1); for (TokenOutputField tokenOutputField: token.getOutputFields()) { final String matchedName = tokenOutputField.getName(); final String matchedType = tokenOutputField.getType(); parsable.addDissection(inputname, matchedType, matchedName, decodeExtractedValue(matchedName, matchedStr)); } } } else { throw new DissectionFailure("The input line does not match the specified log format." + "Line : " + line.getValue() + "\n" + "LogFormat: " + logFormat + "\n" + "RegEx : " + logFormatRegEx); } } // -------------------------------------------- /** * This should be overridden if there is a need to cleanup the * actual logformat before parsing. * @param tokenLogFormat the 'dirty' logformat * @return the cleaned version of the tokenLogFormat. */ protected String cleanupLogFormat(String tokenLogFormat){ return tokenLogFormat; } // -------------------------------------------- @SuppressWarnings({ "PMD.AvoidInstantiatingObjectsInLoops", "PMD.LongVariable", "PMD.ExcessiveMethodLength", "PMD.DataflowAnomalyAnalysis", "PMD.NcssMethodCount", "PMD.NPathComplexity" }) private List parseTokenLogFileDefinition(final String tokenLogFormat) { // Add all available parsers final List tokenParsers = createAllTokenParsers(); final List tokens = new ArrayList<>(50); // We first change all the references to headers to lowercase // because we must handle these as "case insensitive" String cleanedTokenLogFormat = cleanupLogFormat(tokenLogFormat); // Now we let all tokens figure out if they are present in here for (TokenParser tokenParser : tokenParsers) { List newTokens = tokenParser.getTokens(cleanedTokenLogFormat); if (newTokens != null) { tokens.addAll(newTokens); } } // We now have a full list of all matched tokens // --------------------------------------- // We sort them by position of the token in the format specifier tokens.sort(new TokenSorterByStartPos()); // First we take out the duplicates with a lower prio(=relevance score) final List kickTokens = new ArrayList<>(50); Token prevToken = null; for (Token token : tokens) { if (prevToken==null){ prevToken=token; continue; } if (prevToken.getStartPos() == token.getStartPos()) { if (prevToken.getLength() == token.getLength()) { if (prevToken.getPrio() < token.getPrio()) { kickTokens.add(prevToken); } else { kickTokens.add(token); } } else { if (prevToken.getLength() < token.getLength()) { kickTokens.add(prevToken); } else { kickTokens.add(token); } } } else { // Sometimes we find that a part of a token matches another token aswell. // Example: %{%H}t Custom Timeformat (only the hour) also matches the protocol token. // So we kick them of they overlap if (prevToken.getStartPos() + prevToken.getLength() > token.getStartPos()) { kickTokens.add(token); continue; } } prevToken=token; } tokens.removeAll(kickTokens); final List allTokens = new ArrayList<>(50); // We now look for the holes and add "FIXED STRING" tokens int tokenBegin; int tokenEnd = 0; for (Token token : tokens) { tokenBegin = token.getStartPos(); // Space between the begin of the next token and the end of the previous token? if (tokenBegin - tokenEnd > 0) { String separator = cleanedTokenLogFormat.substring(tokenEnd, tokenBegin); Token fixedStringToken = new FixedStringToken(separator, tokenBegin, tokenBegin - tokenEnd, 0); allTokens.add(fixedStringToken); } allTokens.add(token); tokenEnd = tokenBegin + token.getLength(); } int logFormatLength = cleanedTokenLogFormat.length(); if (tokenEnd < logFormatLength) { String separator = cleanedTokenLogFormat.substring(tokenEnd); Token fixedStringToken = new FixedStringToken(separator, tokenEnd, cleanedTokenLogFormat.length() - tokenEnd, 0); allTokens.add(fixedStringToken); } return allTokens; } @Override public void createAdditionalDissectors(Parser parser) { for (Token token: logFormatTokens) { parser.addDissector(token.getCustomDissector()); } } // -------------------------------------------- protected abstract List createAllTokenParsers(); } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/tokenformat/TokenOutputField.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.tokenformat; import nl.basjes.parse.core.Casts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.EnumSet; public class TokenOutputField implements Serializable { private static final Logger LOG = LoggerFactory.getLogger(TokenOutputField.class); private final String type; private final String name; private final EnumSet casts; /** * If this is not null the string is the name of the replacement field */ private String deprecated = null; public TokenOutputField(String type, String name, EnumSet casts) { // RFC 2616 Section 4.2 states: "Field names are case-insensitive." this.name = name.toLowerCase(); this.type = type; this.casts = casts; } public String getType() { return type; } public String getName() { return name; } public EnumSet getCasts() { return casts; } public TokenOutputField deprecateFor(String deprecatedFor) { deprecated = deprecatedFor; return this; } public boolean isDeprecated() { return deprecated != null; } public void wasUsed() { if (deprecated != null) { LOG.warn("------------------------------------------------------------------------"); LOG.warn("The field \"{}:{}\" is deprecated. Use \"{}\" instead.", type, name, deprecated); LOG.warn("------------------------------------------------------------------------"); } } @Override public String toString() { String msg = "{ "+getType()+':'+getName()+" --> "+casts+" }"; if (deprecated != null) { return "DEPRECATED: " + msg; } return msg; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/tokenformat/TokenParser.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.tokenformat; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; public class TokenParser implements Serializable { private static final Logger LOG = LoggerFactory.getLogger(TokenParser.class); // --------------------------------------- public static final String FORMAT_DIGIT = "[0-9]"; public static final String FORMAT_NUMBER = FORMAT_DIGIT + "+"; public static final String FORMAT_CLF_NUMBER = FORMAT_NUMBER + "|-"; public static final String FORMAT_HEXDIGIT = "[0-9a-fA-F]"; public static final String FORMAT_HEXNUMBER = FORMAT_HEXDIGIT + "+"; public static final String FORMAT_CLF_HEXNUMBER = FORMAT_HEXNUMBER + "|-"; public static final String FORMAT_NON_ZERO_NUMBER = "[1-9][0-9]*"; public static final String FORMAT_CLF_NON_ZERO_NUMBER = FORMAT_NON_ZERO_NUMBER + "|-"; public static final String FORMAT_EIGHT_BIT_DECIMAL = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"; // This next regex only allows for the common form of an IPv4 address that appear in a logfile. public static final String FORMAT_IPV4 = "(?:" + FORMAT_EIGHT_BIT_DECIMAL + "\\.){3}" + FORMAT_EIGHT_BIT_DECIMAL; // From http://codepad.org/wo95tiyp public static final String FORMAT_IPV6 = ":?(?:" + FORMAT_HEXDIGIT + "{1,4}(?::|.)?){0,8}(?::|::)?(?:" + FORMAT_HEXDIGIT + "{1,4}(?::|.)?){0,8}"; public static final String FORMAT_IP = FORMAT_IPV4 + "|" + FORMAT_IPV6; public static final String FORMAT_CLF_IP = FORMAT_IP + "|-"; public static final String FORMAT_STRING = ".*?"; public static final String FORMAT_NO_SPACE_STRING = "[^\\s]*"; public static final String FIXED_STRING = "FIXED_STRING"; // This expression "forces" a year in the range [1000-9999] :). public static final String FORMAT_STANDARD_TIME_US = "[0-3][0-9]/(?:[a-zA-Z][a-zA-Z][a-zA-Z])/[1-9][0-9][0-9][0-9]:[0-9][0-9]:[0-9][0-9]:[0-9][0-9] [\\+|\\-][0-9][0-9][0-9][0-9]"; public static final String FORMAT_STANDARD_TIME_ISO8601 = "[1-9][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]T[0-9][0-9]:[0-9][0-9]:[0-9][0-9][\\+|\\-][0-9][0-9]:[0-9][0-9]"; public static final String FORMAT_NUMBER_DECIMAL = FORMAT_NUMBER + "\\." + FORMAT_NUMBER; public static final String FORMAT_NUMBER_OPTIONAL_DECIMAL = FORMAT_NUMBER + "(?:\\." + FORMAT_NUMBER + ")?"; // --------------------------------------- private final String logFormatToken; private final List outputFields = new ArrayList<>(); private final String regex; private final int prio; protected String warningMessageWhenUsed; private final Dissector customDissector; // -------------------------------------------- public TokenParser(final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex) { this(nLogFormatToken, nValueName, nValueType, nCasts, nRegex, 10); } public TokenParser(final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex, final int nPrio) { this(nLogFormatToken, nValueName, nValueType, nCasts, nRegex, nPrio, null); } public TokenParser(final String nLogFormatToken, final String nValueName, final String nValueType, final EnumSet nCasts, final String nRegex, final int nPrio, final Dissector nCustomDissector) { logFormatToken = nLogFormatToken; regex = nRegex; prio = nPrio; customDissector = nCustomDissector; addOutputField(nValueType, nValueName, nCasts); } public TokenParser(final String nLogFormatToken, final String nRegex) { this(nLogFormatToken, nRegex, 0, null); } public TokenParser(final String nLogFormatToken, final String nRegex, final int nPrio) { this(nLogFormatToken, nRegex, nPrio, null); } public TokenParser(final String nLogFormatToken, final String nRegex, final int nPrio, final Dissector nCustomDissector) { logFormatToken = nLogFormatToken; regex = nRegex; prio = nPrio; customDissector = nCustomDissector; } public TokenParser addOutputField(String type, String name, EnumSet casts) { outputFields.add(new TokenOutputField(type, name, casts)); return this; } public TokenParser addOutputField(String type, String name, EnumSet casts, String deprecateFor) { outputFields.add(new TokenOutputField(type, name, casts).deprecateFor(deprecateFor)); return this; } public TokenParser addOutputField(TokenOutputField outputField) { this.outputFields.add(outputField); return this; } public TokenParser addOutputFields(List nOutputFields) { this.outputFields.addAll(nOutputFields); return this; } public List getOutputFields() { return outputFields; } // -------------------------------------------- public TokenParser setWarningMessageWhenUsed(String message) { this.warningMessageWhenUsed = message; return this; } public String getLogFormatToken() { return logFormatToken; } public String getRegex() { return regex; } public int getPrio() { return prio; } public Dissector getCustomDissector() { return customDissector; } // -------------------------------------------- public Token getNextToken(final String logFormat, final int startOffset) { final int pos = logFormat.indexOf(logFormatToken, startOffset); if (pos == -1) { return null; } Token token = new Token( regex, pos, logFormatToken.length(), prio) .addOutputFields(outputFields); if (warningMessageWhenUsed != null) { token.setWarningMessageWhenUsed(warningMessageWhenUsed); } if (!addCustomDissector(token, outputFields.get(0).getType(), outputFields.get(0).getName())) { return null; } return token; } // -------------------------------------------- public List getTokens(final String logFormat) { if (StringUtils.isBlank(logFormat)) { return null; } final List result = new ArrayList<>(5); // Usually a good guess int offset = 0; while (true) { final Token token = getNextToken(logFormat, offset); if (token == null) { break; } result.add(token); offset = token.getStartPos() + token.getLength(); } return result; } // -------------------------------------------- protected boolean addCustomDissector(Token token, String fieldType, String fieldName) { if (customDissector == null) { return true; } try { Dissector dissector = customDissector.getNewInstance(); dissector.setInputType(fieldType); if (!dissector.initializeFromSettingsParameter(fieldName)) { LOG.error("Unable to INITIALIZE custom dissector for {}:{}", fieldType, fieldName); return false; } token.setCustomDissector(dissector); } catch (Exception e) { LOG.error("Unable to add custom dissector for {}:{} because of : {}", fieldType, fieldName, e.getMessage()); return false; } return true; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/tokenformat/TokenSorterByStartPos.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.tokenformat; import java.io.Serializable; import java.util.Comparator; public class TokenSorterByStartPos implements Comparator, Serializable { @Override public int compare(final Token t1, final Token t2) { int startPosDiff = Integer.compare(t1.getStartPos(), t2.getStartPos()); if (startPosDiff != 0) { return startPosDiff; } int lengthDiff = Integer.compare(t1.getLength(), t2.getLength()); if (lengthDiff != 0) { return lengthDiff; } return -1 * Integer.compare(t1.getPrio(), t2.getPrio()); } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/translate/ConvertCLFIntoNumber.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.translate; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.Value; import nl.basjes.parse.core.exceptions.DissectionFailure; public class ConvertCLFIntoNumber extends TypeConvertBaseDissector { public ConvertCLFIntoNumber() { super(); } public ConvertCLFIntoNumber(String nInputType, String nOutputType) { super(nInputType, nOutputType); } @Override public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure { String stringValue = value.getString(); if (stringValue == null || "-".equals(stringValue)) { parsable.addDissection(inputname, outputType, "", 0); } else { parsable.addDissection(inputname, outputType, "", value); } } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/translate/ConvertMillisecondsIntoMicroseconds.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.translate; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.Value; import nl.basjes.parse.core.exceptions.DissectionFailure; public class ConvertMillisecondsIntoMicroseconds extends TypeConvertBaseDissector { public ConvertMillisecondsIntoMicroseconds() { super(); } public ConvertMillisecondsIntoMicroseconds(String inputType, String nOutputType) { super(inputType, nOutputType); } @Override public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure { parsable.addDissection(inputname, outputType, "", value.getLong() * 1000); } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/translate/ConvertNumberIntoCLF.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.translate; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.Value; import nl.basjes.parse.core.exceptions.DissectionFailure; public class ConvertNumberIntoCLF extends TypeConvertBaseDissector { public ConvertNumberIntoCLF() { super(); } public ConvertNumberIntoCLF(String inputType, String nOutputType) { super(inputType, nOutputType); } @Override public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure { parsable.addDissection(inputname, outputType, "", value); } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/translate/ConvertSecondsWithMillisStringDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.translate; import nl.basjes.parse.core.Parsable; import nl.basjes.parse.core.Value; import nl.basjes.parse.core.exceptions.DissectionFailure; public class ConvertSecondsWithMillisStringDissector extends TypeConvertBaseDissector { public ConvertSecondsWithMillisStringDissector() { super(); } public ConvertSecondsWithMillisStringDissector(String inputType, String nOutputType) { super(inputType, nOutputType); } @Override public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure { String[] epochStrings = value.getString().split("\\.", 2); Long seconds = Long.parseLong(epochStrings[0]); Long milliseconds = Long.parseLong(epochStrings[1]); Long epoch = seconds * 1000 + milliseconds; parsable.addDissection(inputname, outputType, "", epoch); } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/java/nl/basjes/parse/httpdlog/dissectors/translate/TypeConvertBaseDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors.translate; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.SimpleDissector; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import java.util.EnumSet; import java.util.HashMap; import static nl.basjes.parse.core.Casts.STRING_OR_LONG; public abstract class TypeConvertBaseDissector extends SimpleDissector { protected String inputType; protected String outputType; public TypeConvertBaseDissector() { super(null, new HashMap<>()); } private static HashMap> fillOutputConfig(String outputType, EnumSet casts) { HashMap> typeConvertConfig = new HashMap<>(); typeConvertConfig.put(outputType + ":", casts); return typeConvertConfig; } public TypeConvertBaseDissector(String nInputType, String nOutputType) { super(nInputType, fillOutputConfig(nOutputType, STRING_OR_LONG)); inputType = nInputType; outputType = nOutputType; } @Override protected void initializeNewInstance(Dissector newInstance) throws InvalidDissectorException { super.initializeNewInstance(newInstance); ((TypeConvertBaseDissector)newInstance).inputType = inputType; ((TypeConvertBaseDissector)newInstance).outputType = outputType; } } ================================================ FILE: httpdlog/httpdlog-parser/src/main/resources/version/Version.java.template ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; public final class Version { public static final String GIT_COMMIT_ID_DESCRIBE_SHORT = "@git.commit.id.describe-short@"; public static final String PROJECT_BUILD_OUTPUTTIMESTAMP = "@project.build.outputTimestamp@"; public static final String PROJECT_VERSION = "@project.version@"; public static String getGitCommitIdDescribeShort() { return GIT_COMMIT_ID_DESCRIBE_SHORT; } public static String getBuildTimestamp() { return PROJECT_BUILD_OUTPUTTIMESTAMP; } public static String getProjectVersion() { return PROJECT_VERSION; } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/ApacheHttpdAllFieldsTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.test.DissectorTester; import org.junit.jupiter.api.Test; import java.util.List; import static org.junit.jupiter.api.Assertions.assertTrue; class ApacheHttpdAllFieldsTest { private void verifyFieldAvailability(String logformat, String... expectedFields) { List possible = DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .getPossible(); for (String expectedField:expectedFields) { assertTrue(possible.contains(expectedField), "Logformat >>>" + logformat + "<<< should produce " + expectedField + " instead we found: " + possible); } } @Test void checkDeprecationMessage() { DissectorTester.create() .withDissector(new HttpdLogFormatDissector("%b %D Deprecated")) .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .withInput("1 2 Deprecated") .expect("BYTES:response.body.bytesclf", "1") .expect("MICROSECONDS:server.process.time", "2") .checkExpectations(); } @Test void testAllFieldsAvailability() { verifyFieldAvailability("%a", "IP:connection.client.ip", "IP:connection.client.ip.last"); verifyFieldAvailability("%a", "IP:connection.client.ip.last"); verifyFieldAvailability("%{c}a", "IP:connection.client.peerip", "IP:connection.client.peerip.last"); verifyFieldAvailability("%<{c}a", "IP:connection.client.peerip.original"); verifyFieldAvailability("%>{c}a", "IP:connection.client.peerip.last"); verifyFieldAvailability("%A", "IP:connection.server.ip", "IP:connection.server.ip.last"); verifyFieldAvailability("%A", "IP:connection.server.ip.last"); verifyFieldAvailability("%B", "BYTES:response.body.bytes", "BYTES:response.body.bytes.last"); verifyFieldAvailability("%B", "BYTES:response.body.bytes.last"); verifyFieldAvailability("%b Deprecated", "BYTES:response.body.bytesclf"); verifyFieldAvailability("%b", "BYTESCLF:response.body.bytes", "BYTESCLF:response.body.bytes.last"); verifyFieldAvailability("%b", "BYTESCLF:response.body.bytes.last"); verifyFieldAvailability("%{FooBar}C", "HTTP.COOKIE:request.cookies.foobar"); verifyFieldAvailability("%{FooBar}e", "VARIABLE:server.environment.foobar"); verifyFieldAvailability("%f", "FILENAME:server.filename", "FILENAME:server.filename.last"); verifyFieldAvailability("%f", "FILENAME:server.filename.last"); verifyFieldAvailability("%h", "IP:connection.client.host", "IP:connection.client.host.last"); verifyFieldAvailability("%h", "IP:connection.client.host.last"); verifyFieldAvailability("%H", "PROTOCOL:request.protocol", "PROTOCOL:request.protocol.last"); verifyFieldAvailability("%H", "PROTOCOL:request.protocol.last"); verifyFieldAvailability("%{FooBar}i", "HTTP.HEADER:request.header.foobar"); verifyFieldAvailability("%{FooBar}^ti", "HTTP.TRAILER:request.trailer.foobar"); verifyFieldAvailability("%k", "NUMBER:connection.keepalivecount", "NUMBER:connection.keepalivecount.last"); verifyFieldAvailability("%k", "NUMBER:connection.keepalivecount.last"); verifyFieldAvailability("%l", "NUMBER:connection.client.logname", "NUMBER:connection.client.logname.last"); verifyFieldAvailability("%l", "NUMBER:connection.client.logname.last"); verifyFieldAvailability("%L", "STRING:request.errorlogid", "STRING:request.errorlogid.last"); verifyFieldAvailability("%L", "STRING:request.errorlogid.last"); verifyFieldAvailability("%m", "HTTP.METHOD:request.method", "HTTP.METHOD:request.method.last"); verifyFieldAvailability("%m", "HTTP.METHOD:request.method.last"); verifyFieldAvailability("%{FooBar}n", "STRING:server.module_note.foobar"); verifyFieldAvailability("%{FooBar}o", "HTTP.HEADER:response.header.foobar"); verifyFieldAvailability("%{FooBar}^to", "HTTP.TRAILER:response.trailer.foobar"); verifyFieldAvailability("%p", "PORT:request.server.port.canonical", "PORT:request.server.port.canonical.last"); verifyFieldAvailability("%p", "PORT:request.server.port.canonical.last"); verifyFieldAvailability("%{canonical}p", "PORT:connection.server.port.canonical", "PORT:connection.server.port.canonical.last"); verifyFieldAvailability("%<{canonical}p", "PORT:connection.server.port.canonical.original"); verifyFieldAvailability("%>{canonical}p", "PORT:connection.server.port.canonical.last"); verifyFieldAvailability("%{local}p", "PORT:connection.server.port", "PORT:connection.server.port.last"); verifyFieldAvailability("%<{local}p", "PORT:connection.server.port.original"); verifyFieldAvailability("%>{local}p", "PORT:connection.server.port.last"); verifyFieldAvailability("%{remote}p", "PORT:connection.client.port", "PORT:connection.client.port.last"); verifyFieldAvailability("%<{remote}p", "PORT:connection.client.port.original"); verifyFieldAvailability("%>{remote}p", "PORT:connection.client.port.last"); verifyFieldAvailability("%P", "NUMBER:connection.server.child.processid", "NUMBER:connection.server.child.processid.last"); verifyFieldAvailability("%P", "NUMBER:connection.server.child.processid.last"); verifyFieldAvailability("%{pid}P", "NUMBER:connection.server.child.processid", "NUMBER:connection.server.child.processid.last"); verifyFieldAvailability("%<{pid}P", "NUMBER:connection.server.child.processid.original"); verifyFieldAvailability("%>{pid}P", "NUMBER:connection.server.child.processid.last"); verifyFieldAvailability("%{tid}P", "NUMBER:connection.server.child.threadid", "NUMBER:connection.server.child.threadid.last"); verifyFieldAvailability("%<{tid}P", "NUMBER:connection.server.child.threadid.original"); verifyFieldAvailability("%>{tid}P", "NUMBER:connection.server.child.threadid.last"); verifyFieldAvailability("%{hextid}P", "NUMBER:connection.server.child.hexthreadid", "NUMBER:connection.server.child.hexthreadid.last"); verifyFieldAvailability("%<{hextid}P", "NUMBER:connection.server.child.hexthreadid.original"); verifyFieldAvailability("%>{hextid}P", "NUMBER:connection.server.child.hexthreadid.last"); verifyFieldAvailability("%q", "HTTP.QUERYSTRING:request.querystring", "HTTP.QUERYSTRING:request.querystring.last"); verifyFieldAvailability("%q", "HTTP.QUERYSTRING:request.querystring.last"); verifyFieldAvailability("%r", "HTTP.FIRSTLINE:request.firstline", "HTTP.FIRSTLINE:request.firstline.original"); verifyFieldAvailability("%r", "HTTP.FIRSTLINE:request.firstline.last"); verifyFieldAvailability("%R", "STRING:request.handler", "STRING:request.handler.last"); verifyFieldAvailability("%R", "STRING:request.handler.last"); verifyFieldAvailability("%s", "STRING:request.status", "STRING:request.status.original"); verifyFieldAvailability("%s", "STRING:request.status.last"); verifyFieldAvailability("%t", "TIME.STAMP:request.receive.time", "TIME.STAMP:request.receive.time.last"); verifyFieldAvailability("%t", "TIME.STAMP:request.receive.time.last"); verifyFieldAvailability("%{%Y}t", "TIME.YEAR:request.receive.time.year"); verifyFieldAvailability("%{begin:%Y}t", "TIME.YEAR:request.receive.time.begin.year"); verifyFieldAvailability("%{end:%Y}t", "TIME.YEAR:request.receive.time.end.year"); verifyFieldAvailability("%{sec}t", "TIME.SECONDS:request.receive.time.sec", "TIME.SECONDS:request.receive.time.sec"); verifyFieldAvailability("%<{sec}t", "TIME.SECONDS:request.receive.time.sec.original"); verifyFieldAvailability("%>{sec}t", "TIME.SECONDS:request.receive.time.sec.last"); verifyFieldAvailability("%{begin:sec}t", "TIME.SECONDS:request.receive.time.begin.sec", "TIME.SECONDS:request.receive.time.begin.sec.last"); verifyFieldAvailability("%<{begin:sec}t", "TIME.SECONDS:request.receive.time.begin.sec.original"); verifyFieldAvailability("%>{begin:sec}t", "TIME.SECONDS:request.receive.time.begin.sec.last"); verifyFieldAvailability("%{end:sec}t", "TIME.SECONDS:request.receive.time.end.sec", "TIME.SECONDS:request.receive.time.end.sec.last"); verifyFieldAvailability("%<{end:sec}t", "TIME.SECONDS:request.receive.time.end.sec.original"); verifyFieldAvailability("%>{end:sec}t", "TIME.SECONDS:request.receive.time.end.sec.last"); verifyFieldAvailability("%{msec}t Deprecated", "TIME.EPOCH:request.receive.time.begin.msec"); verifyFieldAvailability("%{msec}t", "TIME.EPOCH:request.receive.time.msec", "TIME.EPOCH:request.receive.time.msec.last"); verifyFieldAvailability("%<{msec}t", "TIME.EPOCH:request.receive.time.msec.original"); verifyFieldAvailability("%>{msec}t", "TIME.EPOCH:request.receive.time.msec.last"); verifyFieldAvailability("%{begin:msec}t", "TIME.EPOCH:request.receive.time.begin.msec", "TIME.EPOCH:request.receive.time.begin.msec.last"); verifyFieldAvailability("%<{begin:msec}t", "TIME.EPOCH:request.receive.time.begin.msec.original"); verifyFieldAvailability("%>{begin:msec}t", "TIME.EPOCH:request.receive.time.begin.msec.last"); verifyFieldAvailability("%{end:msec}t", "TIME.EPOCH:request.receive.time.end.msec", "TIME.EPOCH:request.receive.time.end.msec.last"); verifyFieldAvailability("%<{end:msec}t", "TIME.EPOCH:request.receive.time.end.msec.original"); verifyFieldAvailability("%>{end:msec}t", "TIME.EPOCH:request.receive.time.end.msec.last"); verifyFieldAvailability("%{usec}t Deprecated", "TIME.EPOCH.USEC:request.receive.time.begin.usec"); verifyFieldAvailability("%{usec}t", "TIME.EPOCH.USEC:request.receive.time.usec", "TIME.EPOCH.USEC:request.receive.time.usec.last"); verifyFieldAvailability("%<{usec}t", "TIME.EPOCH.USEC:request.receive.time.usec.original"); verifyFieldAvailability("%>{usec}t", "TIME.EPOCH.USEC:request.receive.time.usec.last"); verifyFieldAvailability("%{begin:usec}t", "TIME.EPOCH.USEC:request.receive.time.begin.usec", "TIME.EPOCH.USEC:request.receive.time.begin.usec.last"); verifyFieldAvailability("%<{begin:usec}t", "TIME.EPOCH.USEC:request.receive.time.begin.usec.original"); verifyFieldAvailability("%>{begin:usec}t", "TIME.EPOCH.USEC:request.receive.time.begin.usec.last"); verifyFieldAvailability("%{end:usec}t", "TIME.EPOCH.USEC:request.receive.time.end.usec", "TIME.EPOCH.USEC:request.receive.time.end.usec.last"); verifyFieldAvailability("%<{end:usec}t", "TIME.EPOCH.USEC:request.receive.time.end.usec.original"); verifyFieldAvailability("%>{end:usec}t", "TIME.EPOCH.USEC:request.receive.time.end.usec.last"); verifyFieldAvailability("%{msec_frac}t Deprecated", "TIME.EPOCH:request.receive.time.begin.msec_frac"); verifyFieldAvailability("%{msec_frac}t", "TIME.EPOCH:request.receive.time.msec_frac", "TIME.EPOCH:request.receive.time.msec_frac.last"); verifyFieldAvailability("%<{msec_frac}t", "TIME.EPOCH:request.receive.time.msec_frac.original"); verifyFieldAvailability("%>{msec_frac}t", "TIME.EPOCH:request.receive.time.msec_frac.last"); verifyFieldAvailability("%{begin:msec_frac}t", "TIME.EPOCH:request.receive.time.begin.msec_frac", "TIME.EPOCH:request.receive.time.begin.msec_frac.last"); verifyFieldAvailability("%<{begin:msec_frac}t", "TIME.EPOCH:request.receive.time.begin.msec_frac.original"); verifyFieldAvailability("%>{begin:msec_frac}t", "TIME.EPOCH:request.receive.time.begin.msec_frac.last"); verifyFieldAvailability("%{end:msec_frac}t", "TIME.EPOCH:request.receive.time.end.msec_frac", "TIME.EPOCH:request.receive.time.end.msec_frac.last"); verifyFieldAvailability("%<{end:msec_frac}t", "TIME.EPOCH:request.receive.time.end.msec_frac.original"); verifyFieldAvailability("%>{end:msec_frac}t", "TIME.EPOCH:request.receive.time.end.msec_frac.last"); verifyFieldAvailability("%{usec_frac}t Deprecated", "TIME.EPOCH.USEC_FRAC:request.receive.time.begin.usec_frac"); verifyFieldAvailability("%{usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.usec_frac", "TIME.EPOCH.USEC_FRAC:request.receive.time.usec_frac.last"); verifyFieldAvailability("%<{usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.usec_frac.original"); verifyFieldAvailability("%>{usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.usec_frac.last"); verifyFieldAvailability("%{begin:usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.begin.usec_frac", "TIME.EPOCH.USEC_FRAC:request.receive.time.begin.usec_frac.last"); verifyFieldAvailability("%<{begin:usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.begin.usec_frac.original"); verifyFieldAvailability("%>{begin:usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.begin.usec_frac.last"); verifyFieldAvailability("%{end:usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.end.usec_frac", "TIME.EPOCH.USEC_FRAC:request.receive.time.end.usec_frac.last"); verifyFieldAvailability("%<{end:usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.end.usec_frac.original"); verifyFieldAvailability("%>{end:usec_frac}t", "TIME.EPOCH.USEC_FRAC:request.receive.time.end.usec_frac.last"); verifyFieldAvailability("%T", "SECONDS:response.server.processing.time", "SECONDS:response.server.processing.time.original"); verifyFieldAvailability("%T", "SECONDS:response.server.processing.time.last"); verifyFieldAvailability("%D Deprecated", "MICROSECONDS:server.process.time"); verifyFieldAvailability("%D", "MICROSECONDS:response.server.processing.time", "MICROSECONDS:response.server.processing.time.original"); verifyFieldAvailability("%D", "MICROSECONDS:response.server.processing.time.last"); verifyFieldAvailability("%{us}T", "MICROSECONDS:response.server.processing.time", "MICROSECONDS:response.server.processing.time.original"); verifyFieldAvailability("%<{us}T", "MICROSECONDS:response.server.processing.time.original"); verifyFieldAvailability("%>{us}T", "MICROSECONDS:response.server.processing.time.last"); verifyFieldAvailability("%{ms}T", "MILLISECONDS:response.server.processing.time", "MILLISECONDS:response.server.processing.time.original"); verifyFieldAvailability("%<{ms}T", "MILLISECONDS:response.server.processing.time.original"); verifyFieldAvailability("%>{ms}T", "MILLISECONDS:response.server.processing.time.last"); verifyFieldAvailability("%{s}T", "SECONDS:response.server.processing.time", "SECONDS:response.server.processing.time.original"); verifyFieldAvailability("%<{s}T", "SECONDS:response.server.processing.time.original"); verifyFieldAvailability("%>{s}T", "SECONDS:response.server.processing.time.last"); verifyFieldAvailability("%u", "STRING:connection.client.user", "STRING:connection.client.user.last"); verifyFieldAvailability("%u", "STRING:connection.client.user.last"); verifyFieldAvailability("%U", "URI:request.urlpath", "URI:request.urlpath.original"); verifyFieldAvailability("%U", "URI:request.urlpath.last"); verifyFieldAvailability("%v", "STRING:connection.server.name.canonical", "STRING:connection.server.name.canonical.last"); verifyFieldAvailability("%v", "STRING:connection.server.name.canonical.last"); verifyFieldAvailability("%V", "STRING:connection.server.name", "STRING:connection.server.name.last"); verifyFieldAvailability("%V", "STRING:connection.server.name.last"); verifyFieldAvailability("%X", "HTTP.CONNECTSTATUS:response.connection.status", "HTTP.CONNECTSTATUS:response.connection.status.last"); verifyFieldAvailability("%X", "HTTP.CONNECTSTATUS:response.connection.status.last"); verifyFieldAvailability("%I", "BYTES:request.bytes", "BYTES:request.bytes.last"); verifyFieldAvailability("%I", "BYTES:request.bytes.last"); verifyFieldAvailability("%O", "BYTES:response.bytes", "BYTES:response.bytes.last"); verifyFieldAvailability("%O", "BYTES:response.bytes.last"); verifyFieldAvailability("%S", "BYTES:total.bytes", "BYTES:total.bytes.last"); verifyFieldAvailability("%S", "BYTES:total.bytes.last"); verifyFieldAvailability("%{cookie}i", "HTTP.COOKIES:request.cookies", "HTTP.COOKIES:request.cookies.last"); verifyFieldAvailability("%<{cookie}i", "HTTP.COOKIES:request.cookies.original"); verifyFieldAvailability("%>{cookie}i", "HTTP.COOKIES:request.cookies.last"); verifyFieldAvailability("%{set-cookie}o", "HTTP.SETCOOKIES:response.cookies", "HTTP.SETCOOKIES:response.cookies.last"); verifyFieldAvailability("%<{set-cookie}o", "HTTP.SETCOOKIES:response.cookies.original"); verifyFieldAvailability("%>{set-cookie}o", "HTTP.SETCOOKIES:response.cookies.last"); verifyFieldAvailability("%{user-agent}i", "HTTP.USERAGENT:request.user-agent", "HTTP.USERAGENT:request.user-agent.last"); verifyFieldAvailability("%<{user-agent}i", "HTTP.USERAGENT:request.user-agent.original"); verifyFieldAvailability("%>{user-agent}i", "HTTP.USERAGENT:request.user-agent.last"); verifyFieldAvailability("%{referer}i", "HTTP.URI:request.referer", "HTTP.URI:request.referer.last"); verifyFieldAvailability("%<{referer}i", "HTTP.URI:request.referer.original"); verifyFieldAvailability("%>{referer}i", "HTTP.URI:request.referer.last"); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/ApacheHttpdLogParserTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; class ApacheHttpdLogParserTest { // ------------------------------------------ public static class TestRecord { private final Map results = new HashMap<>(32); @SuppressWarnings("UnusedDeclaration") @Field({ "STRING:request.firstline.uri.query.*", "STRING:request.querystring.aap", "IP:connection.client.ip", "NUMBER:connection.client.logname", "STRING:connection.client.user", "TIME.STAMP:request.receive.time", "TIME.SECOND:request.receive.time.second", "HTTP.URI:request.firstline.uri", "STRING:request.status.last", "BYTESCLF:response.body.bytes", "HTTP.URI:request.referer", "STRING:request.referer.query.mies", "STRING:request.referer.query.wim", "HTTP.USERAGENT:request.user-agent", "TIME.DAY:request.receive.time.day", "TIME.HOUR:request.receive.time.hour", "TIME.MONTHNAME:request.receive.time.monthname", "TIME.EPOCH:request.receive.time.epoch", "TIME.WEEK:request.receive.time.weekofweekyear", "TIME.YEAR:request.receive.time.weekyear", "TIME.YEAR:request.receive.time.year", "HTTP.COOKIES:request.cookies", "HTTP.SETCOOKIES:response.cookies", "HTTP.COOKIE:request.cookies.jquery-ui-theme", "HTTP.SETCOOKIE:response.cookies.apache", "STRING:response.cookies.apache.domain", "MICROSECONDS:response.server.processing.time", "STRING:request.status.last", "HTTP.HEADER:response.header.etag"}) public void setValue(final String name, final String value) { results.put(name, value); } public Map getResults() { return results; } } // ------------------------------------------ // LogFormat // "%h %a %A %l %u %t \"%r\" %>s %b %p \"%q\" \"%{Referer}i\" %D \"%{User-agent}i\" \"%{Cookie}i\" \"%{Set-Cookie}o\" " // +"\"%{If-None-Match}i\" \"%{Etag}o\"" // fullcombined private static final String LOG_FORMAT = "%%%h %a %A %l %u %t \"%r\" %>s %b %p \"%q\" \"%!200,304,302{Referer}i\" %D " + "\"%200{User-agent}i\" \"%{Cookie}i\" \"%{Set-Cookie}o\" \"%{If-None-Match}i\" \"%{Etag}o\""; // Because header names are case insensitive we use the lowercase version internally // The modifiers ( like '!200,304,302') are to be removed. // This next value is what should be used internally private static final String EXPECTED_LOG_FORMAT = "%%%h %a %A %l %u [%t] \"%r\" %>s %b %p \"%q\" \"%{referer}i\" %D " + "\"%{user-agent}i\" \"%{cookie}i\" \"%{set-cookie}o\" \"%{if-none-match}i\" \"%{etag}o\""; // ------------------------------------------ /** * Test of initialize method, of class ApacheHttpdLogParser. */ @Test void fullTest1() throws Exception { String line = "%127.0.0.1 127.0.0.1 127.0.0.1 - - [31/Dec/2012:23:49:40 +0100] " + "\"GET /icons/powered_by_rh.png?aap=noot&res=1024x768 HTTP/1.1\" 200 1213 " + "80 \"\" \"http://localhost/index.php?mies=wim\" 351 " + "\"Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0\" " + "\"jquery-ui-theme=Eggplant\" \"Apache=127.0.0.1.1344635380111339; path=/; domain=.basjes.nl\" \"-\" " + "\"\\\"3780ff-4bd-4c1ce3df91380\\\"\""; Parser parser = new HttpdLoglineParser<>(TestRecord.class, LOG_FORMAT); // Manually add an extra dissector parser.addDissector(new ScreenResolutionDissector()); parser.addTypeRemapping("request.firstline.uri.query.res", "SCREENRESOLUTION"); List extraFields = new ArrayList<>(); extraFields.add("SCREENWIDTH:request.firstline.uri.query.res.width"); extraFields.add("SCREENHEIGHT:request.firstline.uri.query.res.height"); parser.addParseTarget(TestRecord.class.getMethod("setValue", String.class, String.class), extraFields); TestRecord record = new TestRecord(); parser.parse(record, line); Map results = record.getResults(); System.out.println(results.toString()); assertEquals("noot", results.get("STRING:request.firstline.uri.query.aap")); assertEquals(null, results.get("STRING:request.firstline.uri.query.foo")); assertEquals(null, results.get("STRING:request.querystring.aap")); assertEquals("1024", results.get("SCREENWIDTH:request.firstline.uri.query.res.width")); assertEquals("768", results.get("SCREENHEIGHT:request.firstline.uri.query.res.height")); assertEquals("127.0.0.1", results.get("IP:connection.client.ip")); assertEquals(null, results.get("NUMBER:connection.client.logname")); assertEquals(null, results.get("STRING:connection.client.user")); assertEquals("31/Dec/2012:23:49:40 +0100", results.get("TIME.STAMP:request.receive.time")); assertEquals("1356994180000", results.get("TIME.EPOCH:request.receive.time.epoch")); assertEquals("1", results.get("TIME.WEEK:request.receive.time.weekofweekyear")); assertEquals("2013", results.get("TIME.YEAR:request.receive.time.weekyear")); assertEquals("2012", results.get("TIME.YEAR:request.receive.time.year")); assertEquals("40", results.get("TIME.SECOND:request.receive.time.second")); assertEquals("/icons/powered_by_rh.png?aap=noot&res=1024x768", results.get("HTTP.URI:request.firstline.uri")); assertEquals("200", results.get("STRING:request.status.last")); assertEquals("1213", results.get("BYTESCLF:response.body.bytes")); assertEquals("http://localhost/index.php?mies=wim", results.get("HTTP.URI:request.referer")); assertEquals("wim", results.get("STRING:request.referer.query.mies")); assertEquals("Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0", results.get("HTTP.USERAGENT:request.user-agent")); assertEquals("31", results.get("TIME.DAY:request.receive.time.day")); assertEquals("23", results.get("TIME.HOUR:request.receive.time.hour")); assertEquals("December", results.get("TIME.MONTHNAME:request.receive.time.monthname")); assertEquals("351", results.get("MICROSECONDS:response.server.processing.time")); assertEquals("Apache=127.0.0.1.1344635380111339; path=/; domain=.basjes.nl", results.get("HTTP.SETCOOKIES:response.cookies")); assertEquals("jquery-ui-theme=Eggplant", results.get("HTTP.COOKIES:request.cookies")); assertEquals("\"3780ff-4bd-4c1ce3df91380\"", results.get("HTTP.HEADER:response.header.etag")); assertEquals("Eggplant", results.get("HTTP.COOKIE:request.cookies.jquery-ui-theme")); assertEquals("Apache=127.0.0.1.1344635380111339; path=/; domain=.basjes.nl", results.get("HTTP.SETCOOKIE:response.cookies.apache")); assertEquals(".basjes.nl", results.get("STRING:response.cookies.apache.domain")); } // ------------------------------------------ @Test void fullTest2() throws Exception { Parser parser = new HttpdLoglineParser<>(TestRecord.class, LOG_FORMAT); String line = "%127.0.0.1 127.0.0.1 127.0.0.1 - - [10/Aug/2012:23:55:11 +0200] \"GET /icons/powered_by_rh.png HTTP/1.1\" 200 1213 80" + " \"\" \"http://localhost/\" 1306 \"Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0\"" + " \"jquery-ui-theme=Eggplant; Apache=127.0.0.1.1344635667182858\" \"-\" \"-\" \"\\\"3780ff-4bd-4c1ce3df91380\\\"\""; TestRecord record = new TestRecord(); parser.parse(record, line); Map results = record.getResults(); assertEquals(null, results.get("HTTP.QUERYSTRING:request.firstline.uri.query.foo")); assertEquals("127.0.0.1", results.get("IP:connection.client.ip")); assertEquals(null, results.get("NUMBER:connection.client.logname")); assertEquals(null, results.get("STRING:connection.client.user")); assertEquals("10/Aug/2012:23:55:11 +0200", results.get("TIME.STAMP:request.receive.time")); assertEquals("11", results.get("TIME.SECOND:request.receive.time.second")); assertEquals("/icons/powered_by_rh.png", results.get("HTTP.URI:request.firstline.uri")); assertEquals("200", results.get("STRING:request.status.last")); assertEquals("1213", results.get("BYTESCLF:response.body.bytes")); assertEquals("http://localhost/", results.get("HTTP.URI:request.referer")); assertEquals("Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0", results.get("HTTP.USERAGENT:request.user-agent")); assertEquals("10", results.get("TIME.DAY:request.receive.time.day")); assertEquals("23", results.get("TIME.HOUR:request.receive.time.hour")); assertEquals("August", results.get("TIME.MONTHNAME:request.receive.time.monthname")); assertEquals("1306", results.get("MICROSECONDS:response.server.processing.time")); assertEquals(null, results.get("HTTP.SETCOOKIES:response.cookies")); assertEquals("jquery-ui-theme=Eggplant; Apache=127.0.0.1.1344635667182858", results.get("HTTP.COOKIES:request.cookies")); assertEquals("\"3780ff-4bd-4c1ce3df91380\"", results.get("HTTP.HEADER:response.header.etag")); // assertEquals("351",results.get("COOKIE:request.cookie.jquery-ui-theme")); } // ------------------------------------------ @Test void fullTestTooLongUri() throws Exception { Parser parser = new HttpdLoglineParser<>(TestRecord.class, LOG_FORMAT); String line = "%127.0.0.1 127.0.0.1 127.0.0.1 - - [10/Aug/2012:23:55:11 +0200] \"GET /ImagineAURLHereThatIsTooLong\" 414 1213 80" + " \"\" \"http://localhost/\" 1306 \"Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0\"" + " \"jquery-ui-theme=Eggplant; Apache=127.0.0.1.1344635667182858\" \"-\" \"-\" \"\\\"3780ff-4bd-4c1ce3df91380\\\"\""; TestRecord record = new TestRecord(); parser.parse(record, line); Map results = record.getResults(); // System.out.println(results.toString()); assertEquals(null, results.get("HTTP.QUERYSTRING:request.firstline.uri.query.foo")); assertEquals("127.0.0.1", results.get("IP:connection.client.ip")); assertEquals(null, results.get("NUMBER:connection.client.logname")); assertEquals(null, results.get("STRING:connection.client.user")); assertEquals("10/Aug/2012:23:55:11 +0200", results.get("TIME.STAMP:request.receive.time")); assertEquals("11", results.get("TIME.SECOND:request.receive.time.second")); assertEquals("/ImagineAURLHereThatIsTooLong", results.get("HTTP.URI:request.firstline.uri")); assertEquals("414", results.get("STRING:request.status.last")); assertEquals("1213", results.get("BYTESCLF:response.body.bytes")); assertEquals("http://localhost/", results.get("HTTP.URI:request.referer")); assertEquals("Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0", results.get("HTTP.USERAGENT:request.user-agent")); assertEquals("10", results.get("TIME.DAY:request.receive.time.day")); assertEquals("23", results.get("TIME.HOUR:request.receive.time.hour")); assertEquals("August", results.get("TIME.MONTHNAME:request.receive.time.monthname")); assertEquals("1306", results.get("MICROSECONDS:response.server.processing.time")); assertEquals(null, results.get("HTTP.SETCOOKIES:response.cookies")); assertEquals("jquery-ui-theme=Eggplant; Apache=127.0.0.1.1344635667182858", results.get("HTTP.COOKIES:request.cookies")); assertEquals("\"3780ff-4bd-4c1ce3df91380\"", results.get("HTTP.HEADER:response.header.etag")); // assertEquals("351",results.get("COOKIE:request.cookie.jquery-ui-theme")); } // ------------------------------------------ public static class TestRecordMissing { @SuppressWarnings({"UnusedDeclaration", "EmptyMethod"}) @Field({ "STRING:request.firstline.uri.query.ThisShouldNOTBeMissing", "HEADER:response.header.Etag.ThisShouldBeMissing" }) public void dummy(final String name, final String value) { } } @Test void testMissing() throws Exception { try { Parser parser = new HttpdLoglineParser<>(TestRecordMissing.class, LOG_FORMAT); parser.parse(""); // Just to trigger the internal assembly of things (that should fail). fail("Missing exception."); } catch (MissingDissectorsException e) { assertTrue(e.getMessage().contains("HEADER:response.header.etag.thisshouldbemissing")); } } // ------------------------------------------ public static class TestRecordMissing2 { @SuppressWarnings({"UnusedDeclaration", "EmptyMethod"}) @Field({ "BLURP:request.firstline.uri.query.ThisShouldBeMissing", "HTTP.HEADER:response.header.etag" }) public void dummy(final String name, final String value) { } } @Test void testMissing2() throws Exception { try { Parser parser = new HttpdLoglineParser<>(TestRecordMissing2.class, LOG_FORMAT); parser.parse(""); // Just to trigger the internal assembly of things (that should fail). fail("Missing exception."); } catch (MissingDissectorsException e) { assertTrue(e.getMessage().contains("BLURP:request.firstline.uri.query.thisshouldbemissing")); } } // ------------------------------------------ @Test void testGetPossiblePaths() { Parser parser = new HttpdLoglineParser<>(TestRecord.class, LOG_FORMAT); List paths = parser.getPossiblePaths(5); assertEquals(true, paths.contains("TIME.SECOND:request.receive.time.second")); assertEquals(true, paths.contains("STRING:request.firstline.uri.query.*")); assertEquals(true, paths.contains("STRING:response.cookies.*.expires")); assertEquals(true, paths.contains("HTTP.HEADER:response.header.etag")); assertEquals(false, paths.contains("FIXED_STRING:fixed_string")); } // ------------------------------------------ @Test void testGetPossiblePathsWithUnusableLogFormat() { Parser parser = new HttpdLoglineParser<>(TestRecord.class, "Empty"); List paths = parser.getPossiblePaths(5); assertTrue(paths == null || paths.isEmpty(), "The output should be empty!"); } // ------------------------------------------ @Test void testLogFormatCleanup(){ ApacheHttpdLogFormatDissector d = new ApacheHttpdLogFormatDissector(); assertEquals("foo", d.cleanupLogFormat("foo")); assertEquals(EXPECTED_LOG_FORMAT, d.cleanupLogFormat(LOG_FORMAT)); assertEquals("%{user-agent}i %% %{referer}i %s %{user-agent}i %% %{referer}i", d.cleanupLogFormat("%400,501{User-agent}i %% %!200,304,302{Referer}i %s %{User-agent}i %% %{Referer}i")); } @Test void verifyCommonFormatNamesMapping() { ApacheHttpdLogFormatDissector dissector = new ApacheHttpdLogFormatDissector("combined"); assertEquals("%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"", dissector.getLogFormat()); } // ------------------------------------------ public static class EmptyTestRecord extends HashMap { @Override public String put(String key, String value) { return super.put(key, value); } private static final long serialVersionUID = 1L; } @Test void testQueryStringDissector() throws Exception { String logformat = "%r"; Parser parser = new HttpdLoglineParser<>(EmptyTestRecord.class, logformat); String[] params = {"STRING:request.firstline.uri.query.foo", "STRING:request.firstline.uri.query.bar", "HTTP.PATH:request.firstline.uri.path", "HTTP.QUERYSTRING:request.firstline.uri.query", "HTTP.REF:request.firstline.uri.ref" }; parser.addParseTarget(EmptyTestRecord.class.getMethod("put", String.class, String.class), Arrays.asList(params)); EmptyTestRecord record = new EmptyTestRecord(); parser.parse(record, "GET /index.html HTTP/1.1"); assertEquals(null, record.get("STRING:request.firstline.uri.query.foo")); assertEquals(null, record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals(null, record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals(null, record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html?foo HTTP/1.1"); assertEquals("", record.get("STRING:request.firstline.uri.query.foo")); assertEquals(null, record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&foo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals(null, record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html&foo HTTP/1.1"); assertEquals("", record.get("STRING:request.firstline.uri.query.foo")); assertEquals(null, record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&foo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals(null, record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html?foo=foofoo# HTTP/1.1"); assertEquals("foofoo", record.get("STRING:request.firstline.uri.query.foo")); assertEquals(null, record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&foo=foofoo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals(null, record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html&foo=foofoo HTTP/1.1"); assertEquals("foofoo", record.get("STRING:request.firstline.uri.query.foo")); assertEquals(null, record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&foo=foofoo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals(null, record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html?bar&foo=foofoo# HTTP/1.1"); assertEquals("foofoo", record.get("STRING:request.firstline.uri.query.foo")); assertEquals("", record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&bar&foo=foofoo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals(null, record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html?bar&foo=foofoo#bookmark HTTP/1.1"); assertEquals("foofoo", record.get("STRING:request.firstline.uri.query.foo")); assertEquals("", record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&bar&foo=foofoo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals("bookmark", record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html?bar=barbar&foo=foofoo#bookmark HTTP/1.1"); assertEquals("foofoo", record.get("STRING:request.firstline.uri.query.foo")); assertEquals("barbar", record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&bar=barbar&foo=foofoo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals("bookmark", record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html&bar=barbar&foo=foofoo#bla HTTP/1.1"); assertEquals("foofoo", record.get("STRING:request.firstline.uri.query.foo")); assertEquals("barbar", record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&bar=barbar&foo=foofoo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals("bla", record.get("HTTP.REF:request.firstline.uri.ref")); record.clear(); parser.parse(record, "GET /index.html&bar=barbar?foo=foofoo HTTP/1.1"); assertEquals("foofoo", record.get("STRING:request.firstline.uri.query.foo")); assertEquals("barbar", record.get("STRING:request.firstline.uri.query.bar")); assertEquals("/index.html", record.get("HTTP.PATH:request.firstline.uri.path")); assertEquals("&bar=barbar&foo=foofoo", record.get("HTTP.QUERYSTRING:request.firstline.uri.query")); assertEquals(null, record.get("HTTP.REF:request.firstline.uri.ref")); } // ------------------------------------------ /** * Test of mod_reqtimeout 408 status code * Assume mod_reqtimeout is enabled and absolutely no data is entered by a client * after making the connection. The result is a http 408 status code and a logline that has proven to * result in several fields failing to be parsed because they are different than the specifications. */ @Test void test408ModReqTimeout() throws Exception { final String logformat = "\"%%\" \"%a\" \"%{c}a\" \"%A\" \"%B\" \"%b\" \"%D\" \"%f\" \"%h\" \"%H\" \"%k\" " + "\"%l\" \"%L\" \"%m\" \"%p\" \"%{canonical}p\" \"%{local}p\" \"%{remote}p\" \"%P\" \"%{pid}P\" \"%{tid}P\"" + " \"%{hextid}P\" \"%q\" \"%r\" \"%R\" \"%s\" \"%>s\" \"%t\" \"%{msec}t\" \"%{begin:msec}t\" \"%{end:msec}t" + "\" \"%{usec}t\" \"%{begin:usec}t\" \"%{end:usec}t\" \"%{msec_frac}t\" \"%{begin:msec_frac}t\" \"%{end:mse" + "c_frac}t\" \"%{usec_frac}t\" \"%{begin:usec_frac}t\" \"%{end:usec_frac}t\" \"%T\" \"%u\" \"%U\" \"%v\" \"" + "%V\" \"%X\" \"%I\" \"%O\" \"%{cookie}i\" \"%{set-cookie}o\" \"%{user-agent}i\" \"%{referer}i\""; String line200 = "\"%\" \"127.0.0.1\" \"127.0.0.1\" \"127.0.0.1\" \"3186\" \"3186\" \"1302\" \"/var/www/html/index.html\" " + "\"127.0.0.1\" \"HTTP/1.1\" \"0\" \"-\" \"-\" \"GET\" \"80\" \"80\" \"80\" \"50142\" \"10344\" \"10344\" " + "\"139854162249472\" \"139854162249472\" \"\" \"GET / HTTP/1.1\" \"-\" \"200\" \"200\" " + "\"[09/Aug/2016:22:57:59 +0200]\" \"1470776279833\" \"1470776279833\" \"1470776279835\" \"1470776279833934\" " + "\"1470776279833934\" \"1470776279835236\" \"833\" \"833\" \"835\" \"833934\" \"833934\" \"835236\" \"0\" " + "\"-\" \"/index.html\" \"committer.lan.basjes.nl\" \"localhost\" \"+\" \"490\" \"3525\" \"-\" \"-\" " + "\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36\" \"-\""; String line408 = "\"%\" \"127.0.0.1\" \"127.0.0.1\" \"127.0.0.1\" \"0\" \"-\" \"34\" \"-\" " + "\"127.0.0.1\" \"HTTP/1.0\" \"0\" \"-\" \"-\" \"-\" \"80\" \"80\" \"80\" \"50150\" \"10344\" \"10344\" " + "\"139854067267328\" \"139854067267328\" \"\" \"-\" \"-\" \"408\" \"408\" " + "\"[09/Aug/2016:22:59:14 +0200]\" \"1470776354625\" \"1470776354625\" \"1470776354625\" \"1470776354625377\" " + "\"1470776354625377\" \"1470776354625411\" \"625\" \"625\" \"625\" \"625377\" \"625377\" \"625411\" \"0\" " + "\"-\" \"-\" \"committer.lan.basjes.nl\" \"committer.lan.basjes.nl\" \"-\" \"0\" \"0\" \"-\" \"-\" \"-\" \"-\""; Parser parser = new HttpdLoglineParser<>(EmptyTestRecord.class, logformat) .addParseTarget(EmptyTestRecord.class.getMethod("put", String.class, String.class), "STRING:request.firstline.uri.query.foo"); parser.parse(new EmptyTestRecord(), line200); parser.parse(new EmptyTestRecord(), line408); } @Test void testFailOnMissingDissectors() { assertThrows(MissingDissectorsException.class, () -> { String line = "[09/Aug/2016:22:57:59 +0200]"; String[] params = { "STRING:request.firstline.uri.query.foo", "TIME.EPOCH:request.receive.time.epoch", }; new HttpdLoglineParser<>(EmptyTestRecord.class, "%t") .addParseTarget(EmptyTestRecord.class.getMethod("put", String.class, String.class), Arrays.asList(params)) .failOnMissingDissectors() .parse(new EmptyTestRecord(), line); }); } @Test void testIgnoreMissingDissectors() throws Exception { String line = "[09/Aug/2016:22:57:59 +0200]"; new HttpdLoglineParser<>(EmptyTestRecord.class, "%t") .addParseTarget(EmptyTestRecord.class.getMethod("put", String.class, String.class), Arrays.asList("STRING:request.firstline.uri.query.foo", "TIME.EPOCH:request.receive.time.epoch")) .ignoreMissingDissectors() .parse(new EmptyTestRecord(), line); } @Test void testExternalExample() { // Found on 2022-06-10 on // https://github.com/cdapio/cdap/blob/develop/cdap-docs/user-guide/source/data-preparation/directives/parse-as-log.rst String logFormat = "%t %u [%D %h %{True-Client-IP}i %{UNIQUE_ID}e %r] %{Cookie}i %s \"%{User-Agent}i\" \"%{host}i\" %l %b %{Referer}i"; String logLine = "[03/Dec/2013:10:53:59 +0000] - [32002 10.102.4.254 195.229.241.182 Up24RwpmBAwAAA1LWJsAAAAR GET " + "/content/dam/Central_Library/Street_Shots/Youth/2012/09sep/LFW/Gallery_03/LFW_SS13_SEPT_12_777.jpg." + "image.W0N539E3452S3991w313.original.jpg HTTP/1.1] __utmc=94539802; dtCookie=EFD9D09B6A2E1789F1329FC1" + "381A356A|_default|1; dtPC=471217988_141#_load_; Carte::KerberosLexicon_getdomain=6701c1320dd96688b2e" + "40b92ce748eee7ae99722; UserData=Username%3ALSHARMA%3AHomepage%3A1%3AReReg%3A0%3ATrialist%3A0%3ALangua" + "ge%3Aen%3ACcode%3Aae%3AForceReReg%3A0; UserID=1375493%3A12345%3A1234567890%3A123%3Accode%3Aae; USER_D" + "ATA=1375493%3ALSharma%3ALokesh%3ASharma%3Alokesh.sharma%40landmarkgroup.com%3A0%3A1%3Aen%3Aae%3A%3Ado" + "main%3A1386060868.51392%3A6701c1320dd96688b2e40b92ce748eee7ae99722; MODE=FONTIS; __utma=94539802.9110" + "97326.1339390457.1386060848.1386065609.190; __utmz=94539802.1384758205.177.38.utmcsr=google|utmccn=(o" + "rganic)|utmcmd=organic|utmctr=(not%20provided); __kti=1339390460526,http%3A%2F%2Fwww.domain.com%2F,;" + "__ktv=28e8-6c4-be3-ce54137d9e48271; WT_FPC=id=2.50.27.157-3067016480.30226245:lv=1386047044279:ss=138" + "6046439530; _opt_vi_3FNG8DZU=42880957-D2F1-4DC5-AF16-FEF88891D24E; __hstc=145721067.750d315a49c642681" + "92826b3911a4e5a.1351772962050.1381151113005.1381297633204.66; hsfirstvisit=http%3A%2F%2Fwww.domain.co" + "m%2F|http%3A%2F%2Fwww.google.co.in%2Furl%3Fsa%3Dt%26rct%3Dj%26q%3Ddomain.com%26source%3Dweb%26cd%3D1%" + "26ved%3D0CB0QFjAA%26url%3Dhttp%3A%2F%2Fwww.domain.com%2F%26ei%3DDmuSULW3AcTLhAfJ24CoDA%26usg%3DAFQjCN" + "GvPmmyn8Bk67OUv-HwjVU4Ff3q1w|1351772962000; hubspotutk=750d315a49c64268192826b3911a4e5a; __ptca=14572" + "1067.jQ7lN5U3C4eN.1351758562.1381136713.1381283233.66; __ptv_62vY4e=jQ7lN5U3C4eN; __pti_62vY4e=jQ7lN5" + "U3C4eN; __ptcz=145721067.1351758562.1.0.ptmcsr=google|ptmcmd=organic|ptmccn=(organic)|ptmctr=domain." + "com; RM=Lsharma%3Ac163b6097f90d2869e537f95900e1c464daa8fb9; wcid=Up2cRApmBAwAAFOiVhcAAAAH%3Af32e5e5f5" + "b593175bfc71af082ab26e4055efeb6; __utmb=94539802.71.9.1386067462709; edge_auth=ip%3D195.229.241.182~" + "expires%3D1386069280~access%3D%2Fapps%2F%2A%21%2Fbin%2F%2A%21%2Fcontent%2F%2A%21%2Fetc%2F%2A%21%2Fho" + "me%2F%2A%21%2Flibs%2F%2A%21%2Freport%2F%2A%21%2Fsection%2F%2A%21%2Fdomain%2F%2A~md5%3D5b47f341723924" + "87dcd44c1d837e2e54; has_js=1; SECTION=%2Fcontent%2Fsection%2Finspiration-design%2Fstreet-shots.html;" + "JSESSIONID=b9377099-7708-45ae-b6e7-c575ffe82187; WT_FPC=id=2.50.27.157-3067016480.30226245:lv=138605" + "3618209:ss=1386053618209; USER_GROUP=LSharma%3Afalse; NSC_wtfswfs_xfcgbsn40-41=ffffffff096e1a1d45525" + "d5f4f58455e445a4a423660 200 \"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)\" " + "\"www.domain.com\" - 24516 http://www.domain.com/content/report/Street_Shots/Youth/Global_round_up/201" + "3/01_Jan/mens_youth_stylingglobalround-up1.html"; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(nl.basjes.parse.core.test.TestRecord.class, logFormat) .addTypeRemapping("server.environment.unique_id", "MOD_UNIQUE_ID")) .withInput(logLine) .printPossible() .printAllPossibleValues() // A normal field .expect("IP:connection.client.host", "10.102.4.254") // The timestamp was parsed and normalized to the Epoch milliseconds .expect("TIME.EPOCH:request.receive.time.epoch", "1386068039000") // A cookie with a very strange name .expect("HTTP.COOKIE:request.cookies.carte::kerberoslexicon_getdomain", "6701c1320dd96688b2e40b92ce748eee7ae99722") // A cookie value that needed a lot of decoding .expect("HTTP.COOKIE:request.cookies.hsfirstvisit", "http://www.domain.com/|http://www.google.co.in/url?sa=t&rct=j&q=domain.com&source=web&cd=1&ved=0CB0QFjAA&url=http://www.domain.com/&ei=DmuSULW3AcTLhAfJ24CoDA&usg=AFQjCNGvPmmyn8Bk67OUv-HwjVU4Ff3q1w|1351772962000") // This is the IP which was extracted from the UNIQUE_ID ( "Up24RwpmBAwAAA1LWJsAAAAR" in this case). .expect("IP:server.environment.unique_id.ip", "10.102.4.12") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/BasicOverallTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Parser; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertEquals; class BasicOverallTest { public static class MyRecord { private final List results = new ArrayList<>(); @SuppressWarnings({"unused"}) // Used via reflection public void setValue(final String name, final String value) { results.add(name + '=' + value); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(" ----------- BEGIN ----------\n"); for (String value : results) { sb.append(value).append('\n'); } sb.append(" ------------ END -----------\n"); sb.append("\n"); return sb.toString(); } public void clear() { results.clear(); } } private static final String LOG_FORMAT = "\"%%\" \"%a\" \"%{c}a\" \"%A\" \"%B\" \"%b\" \"%D\" \"%f\" \"%h\" \"%H\" \"%k\" " + "\"%l\" \"%L\" \"%m\" \"%p\" \"%{canonical}p\" \"%{local}p\" \"%{remote}p\" \"%P\" \"%{pid}P\" \"%{tid}P\"" + " \"%{hextid}P\" \"%q\" \"%r\" \"%R\" \"%s\" \"%>s\" \"%t\" \"%{msec}t\" \"%{begin:msec}t\" \"%{end:msec}t" + "\" \"%{usec}t\" \"%{begin:usec}t\" \"%{end:usec}t\" \"%{msec_frac}t\" \"%{begin:msec_frac}t\" \"%{end:mse" + "c_frac}t\" \"%{usec_frac}t\" \"%{begin:usec_frac}t\" \"%{end:usec_frac}t\" \"%T\" \"%u\" \"%U\" \"%v\" \"" + "%V\" \"%X\" \"%I\" \"%O\" \"%{cookie}i\" \"%{set-cookie}o\" \"%{user-agent}i\" \"%{referer}i\""; private static final String[] LOG_LINES = { "\"%\" \"172.17.42.1\" \"172.17.42.1\" \"172.17.0.2\" \"4880\" \"4880\" \"652\" \"/usr/share/httpd/noindex/ind" + "ex.html\" \"172.17.42.1\" \"HTTP/1.1\" \"0\" \"-\" \"VG9exZ0MX@uqta4OldejvQAAAAA\" \"GET\" \"80\" \"8" + "0\" \"80\" \"43417\" \"126\" \"126\" \"140597540726848\" \"140597540726848\" \"\" \"GET / HTTP/1.1\" " + "\"httpd/unix-directory\" \"403\" \"403\" \"[21/Nov/2014:15:48:21 +0000]\" \"1416584901018\" \"1416584" + "901018\" \"1416584901018\" \"1416584901018010\" \"1416584901018010\" \"1416584901018670\" \"018\" \"0" + "18\" \"018\" \"018010\" \"018010\" \"018670\" \"0\" \"-\" \"/\" \"172.17.0.2\" \"172.17.0.2\" \"+\" " + "\"367\" \"5188\" \"-\" \"-\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)" + " Chrome/38.0.2125.122 Safari/537.36\" \"-\"", "\"%\" \"172.17.42.1\" \"172.17.42.1\" \"172.17.0.2\" \"0\" \"-\" \"302\" \"/usr/share/httpd/noindex/css/boots" + "trap.min.css\" \"172.17.42.1\" \"HTTP/1.1\" \"1\" \"-\" \"-\" \"GET\" \"80\" \"80\" \"80\" \"43417\" " + "\"126\" \"126\" \"140597540726848\" \"140597540726848\" \"\" \"GET /css/bootstrap.min.css HTTP/1.1\" " + "\"-\" \"304\" \"304\" \"[21/Nov/2014:15:48:21 +0000]\" \"1416584901087\" \"1416584901087\" \"14165849" + "01087\" \"1416584901087115\" \"1416584901087115\" \"1416584901087417\" \"087\" \"087\" \"087\" \"0871" + "15\" \"087115\" \"087417\" \"0\" \"-\" \"/css/bootstrap.min.css\" \"172.17.0.2\" \"172.17.0.2\" \"+\"" + " \"448\" \"180\" \"-\" \"-\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)" + " Chrome/38.0.2125.122 Safari/537.36\" \"http://172.17.0.2/\"", "\"%\" \"172.17.42.1\" \"172.17.42.1\" \"172.17.0.2\" \"0\" \"-\" \"373\" \"/usr/share/httpd/noindex/css/open-" + "sans.css\" \"172.17.42.1\" \"HTTP/1.1\" \"0\" \"-\" \"-\" \"GET\" \"80\" \"80\" \"80\" \"43418\" \"12" + "7\" \"127\" \"140597540726848\" \"140597540726848\" \"\" \"GET /css/open-sans.css HTTP/1.1\" \"-\" \"" + "304\" \"304\" \"[21/Nov/2014:15:48:21 +0000]\" \"1416584901087\" \"1416584901087\" \"1416584901087\" " + "\"1416584901087430\" \"1416584901087430\" \"1416584901087803\" \"087\" \"087\" \"087\" \"087430\" \"0" + "87430\" \"087803\" \"0\" \"-\" \"/css/open-sans.css\" \"172.17.0.2\" \"172.17.0.2\" \"+\" \"444\" \"1" + "81\" \"-\" \"-\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0" + ".2125.122 Safari/537.36\" \"http://172.17.0.2/\"", "\"%\" \"172.17.42.1\" \"172.17.42.1\" \"172.17.0.2\" \"0\" \"-\" \"381\" \"/usr/share/httpd/noindex/images/ap" + "ache_pb.gif\" \"172.17.42.1\" \"HTTP/1.1\" \"0\" \"-\" \"-\" \"GET\" \"80\" \"80\" \"80\" \"43419\" " + "\"128\" \"128\" \"140597540726848\" \"140597540726848\" \"\" \"GET /images/apache_pb.gif HTTP/1.1\" " + "\"-\" \"304\" \"304\" \"[21/Nov/2014:15:48:21 +0000]\" \"1416584901087\" \"1416584901087\" \"14165849" + "01087\" \"1416584901087445\" \"1416584901087445\" \"1416584901087826\" \"087\" \"087\" \"087\" \"0874" + "45\" \"087445\" \"087826\" \"0\" \"-\" \"/images/apache_pb.gif\" \"172.17.0.2\" \"172.17.0.2\" \"+\" " + "\"448\" \"180\" \"-\" \"-\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/38.0.2125.122 Safari/537.36\" \"http://172.17.0.2/\"", "\"%\" \"172.17.42.1\" \"172.17.42.1\" \"172.17.0.2\" \"0\" \"-\" \"269\" \"/usr/share/httpd/noindex/images/po" + "weredby.png\" \"172.17.42.1\" \"HTTP/1.1\" \"1\" \"-\" \"-\" \"GET\" \"80\" \"80\" \"80\" \"43419\" " + "\"128\" \"128\" \"140597540726848\" \"140597540726848\" \"\" \"GET /images/poweredby.png HTTP/1.1\" " + "\"-\" \"304\" \"304\" \"[21/Nov/2014:15:48:21 +0000]\" \"1416584901091\" \"1416584901091\" \"14165849" + "01091\" \"1416584901091601\" \"1416584901091601\" \"1416584901091870\" \"091\" \"091\" \"091\" \"0916" + "01\" \"091601\" \"091870\" \"0\" \"-\" \"/images/poweredby.png\" \"172.17.0.2\" \"172.17.0.2\" \"+\" " + "\"448\" \"179\" \"-\" \"-\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/38.0.2125.122 Safari/537.36\" \"http://172.17.0.2/\"", "\"%\" \"172.17.42.1\" \"172.17.42.1\" \"172.17.0.2\" \"213\" \"213\" \"448\" \"/var/www/html/ladkshjfkjasdhf" + "\" \"172.17.42.1\" \"HTTP/1.1\" \"0\" \"-\" \"-\" \"GET\" \"80\" \"80\" \"80\" \"43482\" \"136\" \"13" + "6\" \"140597540726848\" \"140597540726848\" \"\" \"GET /ladkshjfkjasdhf HTTP/1.1\" \"-\" \"404\" \"40" + "4\" \"[21/Nov/2014:15:50:45 +0000]\" \"1416585045231\" \"1416585045231\" \"1416585045231\" \"14165850" + "45231085\" \"1416585045231085\" \"1416585045231533\" \"231\" \"231\" \"231\" \"231085\" \"231085\" \"" + "231533\" \"0\" \"-\" \"/ladkshjfkjasdhf\" \"172.17.0.2\" \"172.17.0.2\" \"+\" \"356\" \"429\" \"-\" " + "\"-\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.122 S" + "afari/537.36\" \"-\"", }; @Test void testBasicParsing() throws Exception { Parser parser = new HttpdLoglineParser<>(MyRecord.class, LOG_FORMAT); MyRecord record = new MyRecord(); List paths = parser.getPossiblePaths(); parser.addParseTarget(record.getClass().getMethod("setValue", String.class, String.class), paths); for (String logline : LOG_LINES) { record.clear(); parser.parse(record, logline); System.out.println(record); } } @Test void ensureAllOutputsAreThere() { Parser parser = new HttpdLoglineParser<>(MyRecord.class, LOG_FORMAT); List paths = parser.getPossiblePaths(15, true); // Get the list presorted String pathString = paths .stream() .map(s -> String.format("%-30s: %s", s.substring(0, s.indexOf(':')), s.substring(s.indexOf(':')+1))) .collect(Collectors.joining("\n")); String expectedPaths = "IP : connection.client.host.last\n" + "IP : connection.client.host\n" + "IP : connection.client.ip.last\n" + "IP : connection.client.ip\n" + "NUMBER : connection.client.logname.last\n" + "NUMBER : connection.client.logname\n" + "IP : connection.client.peerip.last\n" + "IP : connection.client.peerip\n" + "PORT : connection.client.port.last\n" + "PORT : connection.client.port\n" + "STRING : connection.client.user.last\n" + "STRING : connection.client.user\n" + "NUMBER : connection.keepalivecount.last\n" + "NUMBER : connection.keepalivecount\n" + "NUMBER : connection.server.child.hexthreadid.last\n" + "NUMBER : connection.server.child.hexthreadid\n" + "NUMBER : connection.server.child.processid.last\n" + "NUMBER : connection.server.child.processid\n" + "NUMBER : connection.server.child.threadid.last\n" + "NUMBER : connection.server.child.threadid\n" + "IP : connection.server.ip.last\n" + "IP : connection.server.ip\n" + "STRING : connection.server.name.canonical.last\n" + "STRING : connection.server.name.canonical\n" + "STRING : connection.server.name.last\n" + "STRING : connection.server.name\n" + "PORT : connection.server.port.canonical.last\n" + "PORT : connection.server.port.canonical\n" + "PORT : connection.server.port.last\n" + "PORT : connection.server.port\n" + "BYTES : request.bytes.last\n" + "BYTESCLF : request.bytes.last\n" + "BYTES : request.bytes\n" + "BYTESCLF : request.bytes\n" + "HTTP.COOKIE : request.cookies.*\n" + "HTTP.COOKIE : request.cookies.last.*\n" + "HTTP.COOKIES : request.cookies.last\n" + "HTTP.COOKIES : request.cookies\n" + "STRING : request.errorlogid.last\n" + "STRING : request.errorlogid\n" + "HTTP.METHOD : request.firstline.method\n" + "HTTP.METHOD : request.firstline.original.method\n" + "HTTP.PROTOCOL.VERSION : request.firstline.original.protocol.version\n" + "HTTP.PROTOCOL : request.firstline.original.protocol\n" + "HTTP.PROTOCOL_VERSION : request.firstline.original.protocol\n" + "HTTP.HOST : request.firstline.original.uri.host\n" + "HTTP.PATH : request.firstline.original.uri.path\n" + "HTTP.PORT : request.firstline.original.uri.port\n" + "HTTP.PROTOCOL : request.firstline.original.uri.protocol\n" + "STRING : request.firstline.original.uri.query.*\n" + "HTTP.QUERYSTRING : request.firstline.original.uri.query\n" + "HTTP.REF : request.firstline.original.uri.ref\n" + "HTTP.USERINFO : request.firstline.original.uri.userinfo\n" + "HTTP.URI : request.firstline.original.uri\n" + "HTTP.FIRSTLINE : request.firstline.original\n" + "HTTP.PROTOCOL.VERSION : request.firstline.protocol.version\n" + "HTTP.PROTOCOL : request.firstline.protocol\n" + "HTTP.PROTOCOL_VERSION : request.firstline.protocol\n" + "HTTP.HOST : request.firstline.uri.host\n" + "HTTP.PATH : request.firstline.uri.path\n" + "HTTP.PORT : request.firstline.uri.port\n" + "HTTP.PROTOCOL : request.firstline.uri.protocol\n" + "STRING : request.firstline.uri.query.*\n" + "HTTP.QUERYSTRING : request.firstline.uri.query\n" + "HTTP.REF : request.firstline.uri.ref\n" + "HTTP.USERINFO : request.firstline.uri.userinfo\n" + "HTTP.URI : request.firstline.uri\n" + "HTTP.FIRSTLINE : request.firstline\n" + "STRING : request.handler.last\n" + "STRING : request.handler\n" + "HTTP.METHOD : request.method.last\n" + "HTTP.METHOD : request.method\n" + "PROTOCOL : request.protocol.last\n" + "PROTOCOL : request.protocol\n" + "STRING : request.querystring.*\n" + "STRING : request.querystring.last.*\n" + "HTTP.QUERYSTRING : request.querystring.last\n" + "HTTP.QUERYSTRING : request.querystring\n" + "TIME.EPOCH : request.receive.time.begin.msec.last\n" + "TIME.EPOCH : request.receive.time.begin.msec\n" + "TIME.EPOCH : request.receive.time.begin.msec_frac.last\n" + "TIME.EPOCH : request.receive.time.begin.msec_frac\n" + "TIME.EPOCH.USEC : request.receive.time.begin.usec.last\n" + "TIME.EPOCH.USEC : request.receive.time.begin.usec\n" + "TIME.EPOCH.USEC_FRAC : request.receive.time.begin.usec_frac.last\n" + "TIME.EPOCH.USEC_FRAC : request.receive.time.begin.usec_frac\n" + "TIME.DATE : request.receive.time.date\n" + "TIME.DATE : request.receive.time.date_utc\n" + "TIME.DAY : request.receive.time.day\n" + "TIME.DAY : request.receive.time.day_utc\n" + "TIME.EPOCH : request.receive.time.end.msec.last\n" + "TIME.EPOCH : request.receive.time.end.msec\n" + "TIME.EPOCH : request.receive.time.end.msec_frac.last\n" + "TIME.EPOCH : request.receive.time.end.msec_frac\n" + "TIME.EPOCH.USEC : request.receive.time.end.usec.last\n" + "TIME.EPOCH.USEC : request.receive.time.end.usec\n" + "TIME.EPOCH.USEC_FRAC : request.receive.time.end.usec_frac.last\n" + "TIME.EPOCH.USEC_FRAC : request.receive.time.end.usec_frac\n" + "TIME.EPOCH : request.receive.time.epoch\n" + "TIME.HOUR : request.receive.time.hour\n" + "TIME.HOUR : request.receive.time.hour_utc\n" + "TIME.DATE : request.receive.time.last.date\n" + "TIME.DATE : request.receive.time.last.date_utc\n" + "TIME.DAY : request.receive.time.last.day\n" + "TIME.DAY : request.receive.time.last.day_utc\n" + "TIME.EPOCH : request.receive.time.last.epoch\n" + "TIME.HOUR : request.receive.time.last.hour\n" + "TIME.HOUR : request.receive.time.last.hour_utc\n" + "TIME.MICROSECOND : request.receive.time.last.microsecond\n" + "TIME.MICROSECOND : request.receive.time.last.microsecond_utc\n" + "TIME.MILLISECOND : request.receive.time.last.millisecond\n" + "TIME.MILLISECOND : request.receive.time.last.millisecond_utc\n" + "TIME.MINUTE : request.receive.time.last.minute\n" + "TIME.MINUTE : request.receive.time.last.minute_utc\n" + "TIME.MONTH : request.receive.time.last.month\n" + "TIME.MONTH : request.receive.time.last.month_utc\n" + "TIME.MONTHNAME : request.receive.time.last.monthname\n" + "TIME.MONTHNAME : request.receive.time.last.monthname_utc\n" + "TIME.NANOSECOND : request.receive.time.last.nanosecond\n" + "TIME.NANOSECOND : request.receive.time.last.nanosecond_utc\n" + "TIME.SECOND : request.receive.time.last.second\n" + "TIME.SECOND : request.receive.time.last.second_utc\n" + "TIME.TIME : request.receive.time.last.time\n" + "TIME.TIME : request.receive.time.last.time_utc\n" + "TIME.ZONE : request.receive.time.last.timezone\n" + "TIME.WEEK : request.receive.time.last.weekofweekyear\n" + "TIME.WEEK : request.receive.time.last.weekofweekyear_utc\n" + "TIME.YEAR : request.receive.time.last.weekyear\n" + "TIME.YEAR : request.receive.time.last.weekyear_utc\n" + "TIME.YEAR : request.receive.time.last.year\n" + "TIME.YEAR : request.receive.time.last.year_utc\n" + "TIME.STAMP : request.receive.time.last\n" + "TIME.MICROSECOND : request.receive.time.microsecond\n" + "TIME.MICROSECOND : request.receive.time.microsecond_utc\n" + "TIME.MILLISECOND : request.receive.time.millisecond\n" + "TIME.MILLISECOND : request.receive.time.millisecond_utc\n" + "TIME.MINUTE : request.receive.time.minute\n" + "TIME.MINUTE : request.receive.time.minute_utc\n" + "TIME.MONTH : request.receive.time.month\n" + "TIME.MONTH : request.receive.time.month_utc\n" + "TIME.MONTHNAME : request.receive.time.monthname\n" + "TIME.MONTHNAME : request.receive.time.monthname_utc\n" + "TIME.EPOCH : request.receive.time.msec.last\n" + "TIME.EPOCH : request.receive.time.msec\n" + "TIME.EPOCH : request.receive.time.msec_frac.last\n" + "TIME.EPOCH : request.receive.time.msec_frac\n" + "TIME.NANOSECOND : request.receive.time.nanosecond\n" + "TIME.NANOSECOND : request.receive.time.nanosecond_utc\n" + "TIME.SECOND : request.receive.time.second\n" + "TIME.SECOND : request.receive.time.second_utc\n" + "TIME.TIME : request.receive.time.time\n" + "TIME.TIME : request.receive.time.time_utc\n" + "TIME.ZONE : request.receive.time.timezone\n" + "TIME.EPOCH.USEC : request.receive.time.usec.last\n" + "TIME.EPOCH.USEC : request.receive.time.usec\n" + "TIME.EPOCH.USEC_FRAC : request.receive.time.usec_frac.last\n" + "TIME.EPOCH.USEC_FRAC : request.receive.time.usec_frac\n" + "TIME.WEEK : request.receive.time.weekofweekyear\n" + "TIME.WEEK : request.receive.time.weekofweekyear_utc\n" + "TIME.YEAR : request.receive.time.weekyear\n" + "TIME.YEAR : request.receive.time.weekyear_utc\n" + "TIME.YEAR : request.receive.time.year\n" + "TIME.YEAR : request.receive.time.year_utc\n" + "TIME.STAMP : request.receive.time\n" + "HTTP.HOST : request.referer.host\n" + "HTTP.HOST : request.referer.last.host\n" + "HTTP.PATH : request.referer.last.path\n" + "HTTP.PORT : request.referer.last.port\n" + "HTTP.PROTOCOL : request.referer.last.protocol\n" + "STRING : request.referer.last.query.*\n" + "HTTP.QUERYSTRING : request.referer.last.query\n" + "HTTP.REF : request.referer.last.ref\n" + "HTTP.USERINFO : request.referer.last.userinfo\n" + "HTTP.URI : request.referer.last\n" + "HTTP.PATH : request.referer.path\n" + "HTTP.PORT : request.referer.port\n" + "HTTP.PROTOCOL : request.referer.protocol\n" + "STRING : request.referer.query.*\n" + "HTTP.QUERYSTRING : request.referer.query\n" + "HTTP.REF : request.referer.ref\n" + "HTTP.USERINFO : request.referer.userinfo\n" + "HTTP.URI : request.referer\n" + "PORT : request.server.port.canonical.last\n" + "PORT : request.server.port.canonical\n" + "STRING : request.status.last\n" + "STRING : request.status.original\n" + "STRING : request.status\n" + "URI : request.urlpath.original\n" + "URI : request.urlpath\n" + "HTTP.USERAGENT : request.user-agent.last\n" + "HTTP.USERAGENT : request.user-agent\n" + "BYTES : response.body.bytes.last\n" + "BYTESCLF : response.body.bytes.last\n" + "BYTES : response.body.bytes\n" + "BYTESCLF : response.body.bytes\n" + "BYTES : response.body.bytesclf\n" + "BYTESCLF : response.body.bytesclf\n" + "BYTES : response.bytes.last\n" + "BYTESCLF : response.bytes.last\n" + "BYTES : response.bytes\n" + "BYTESCLF : response.bytes\n" + "HTTP.CONNECTSTATUS : response.connection.status.last\n" + "HTTP.CONNECTSTATUS : response.connection.status\n" + "STRING : response.cookies.*.comment\n" + "STRING : response.cookies.*.domain\n" + "STRING : response.cookies.*.expires\n" + "TIME.EPOCH : response.cookies.*.expires\n" + "STRING : response.cookies.*.path\n" + "STRING : response.cookies.*.value\n" + "HTTP.SETCOOKIE : response.cookies.*\n" + "STRING : response.cookies.last.*.comment\n" + "STRING : response.cookies.last.*.domain\n" + "STRING : response.cookies.last.*.expires\n" + "TIME.EPOCH : response.cookies.last.*.expires\n" + "STRING : response.cookies.last.*.path\n" + "STRING : response.cookies.last.*.value\n" + "HTTP.SETCOOKIE : response.cookies.last.*\n" + "HTTP.SETCOOKIES : response.cookies.last\n" + "HTTP.SETCOOKIES : response.cookies\n" + "MICROSECONDS : response.server.processing.time.original\n" + "SECONDS : response.server.processing.time.original\n" + "MICROSECONDS : response.server.processing.time\n" + "SECONDS : response.server.processing.time\n" + "FILENAME : server.filename.last\n" + "FILENAME : server.filename\n" + "MICROSECONDS : server.process.time"; assertEquals(expectedPaths, pathString); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/ClientHintsTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import org.junit.jupiter.api.Test; class ClientHintsTest { @Test void testClientHintsWithEscapedDoubleQuotes() { String logFormat = "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Sec-CH-UA}i\" \"%{Sec-CH-UA-Arch}i\" \"%{Sec-CH-UA-Bitness}i\" \"%{Sec-CH-UA-Full-Version}i\" \"%{Sec-CH-UA-Full-Version-List}i\" \"%{Sec-CH-UA-Mobile}i\" \"%{Sec-CH-UA-Model}i\" \"%{Sec-CH-UA-Platform}i\" \"%{Sec-CH-UA-Platform-Version}i\" \"%{Sec-CH-UA-WoW64}i\" %V"; // 10.20.30.40 - - [03/May/2022:14:08:37 +0200] "GET / HTTP/1.1" 200 16165 "https://github.com/nielsbasjes/yauaa" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36" "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"100\", \"Google Chrome\";v=\"100\"" "\"x86\"" "\"64\"" "\"100.0.4896.88\"" "\" Not A;Brand\";v=\"99.0.0.0\", \"Chromium\";v=\"100.0.4896.88\", \"Google Chrome\";v=\"100.0.4896.88\"" "?0" "\"\"" "\"macOS\"" "\"12.2.1\"" "?0" try.yauaa.basjes.nl String testLine = "10.20.30.40 - - [03/May/2022:14:08:37 +0200] \"GET / HTTP/1.1\" 200 16165 \"https://github.com/nielsbasjes/yauaa\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36\" \"\\\" Not A;Brand\\\";v=\\\"99\\\", \\\"Chromium\\\";v=\\\"100\\\", \\\"Google Chrome\\\";v=\\\"100\\\"\" \"\\\"x86\\\"\" \"\\\"64\\\"\" \"\\\"100.0.4896.88\\\"\" \"\\\" Not A;Brand\\\";v=\\\"99.0.0.0\\\", \\\"Chromium\\\";v=\\\"100.0.4896.88\\\", \\\"Google Chrome\\\";v=\\\"100.0.4896.88\\\"\" \"?0\" \"\\\"\\\"\" \"\\\"macOS\\\"\" \"\\\"12.2.1\\\"\" \"?0\" try.yauaa.basjes.nl"; DissectorTester.create() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(testLine) // .getPossible().forEach(System.out::println); .expect("HTTP.USERAGENT:request.user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36") .expect("HTTP.HEADER:request.header.sec-ch-ua", "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"100\", \"Google Chrome\";v=\"100\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-arch", "\"x86\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-bitness", "\"64\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-full-version", "\"100.0.4896.88\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-full-version-list", "\" Not A;Brand\";v=\"99.0.0.0\", \"Chromium\";v=\"100.0.4896.88\", \"Google Chrome\";v=\"100.0.4896.88\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-mobile", "?0") .expect("HTTP.HEADER:request.header.sec-ch-ua-model", "\"\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-platform", "\"macOS\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-platform-version", "\"12.2.1\"") .expect("HTTP.HEADER:request.header.sec-ch-ua-wow64", "?0") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/CookiesTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; class CookiesTest { private static final class EmptyTestRecord { } public static class TestRecord { private final Map results = new HashMap<>(32); private final Map longResults = new HashMap<>(32); @SuppressWarnings({"unused"}) // Used via reflection @Field({ "HTTP.QUERYSTRING:request.firstline.uri.query", "IP:connection.client.ip", "NUMBER:connection.client.logname", "STRING:connection.client.user", "HTTP.URI:request.firstline.uri", "STRING:request.status.last", "BYTESCLF:response.body.bytes", "HTTP.URI:request.referer", "HTTP.USERAGENT:request.user-agent", "TIME.STAMP:request.receive.time", "TIME.EPOCH:request.receive.time.epoch", "TIME.SECOND:request.receive.time.second", "TIME.DAY:request.receive.time.day", "TIME.HOUR:request.receive.time.hour", "TIME.MONTH:request.receive.time.month", "TIME.YEAR:request.receive.time.year", "TIME.MONTHNAME:request.receive.time.monthname", "TIME.SECOND:request.receive.time.second_utc", "TIME.DAY:request.receive.time.day_utc", "TIME.HOUR:request.receive.time.hour_utc", "TIME.MONTH:request.receive.time.month_utc", "TIME.YEAR:request.receive.time.year_utc", "TIME.MONTHNAME:request.receive.time.monthname_utc", "MICROSECONDS:response.server.processing.time", "STRING:request.status.last", "HTTP.HEADER:response.header.etag", // Cookies "HTTP.COOKIES:request.cookies", // "HTTP.COOKIE:request.cookies.apache" , // "HTTP.COOKIE:request.cookies.jquery-ui-theme", "HTTP.COOKIE:request.cookies.*", "HTTP.SETCOOKIES:response.cookies", "HTTP.SETCOOKIE:response.cookies.nba-4", "STRING:response.cookies.nba-4.value", "STRING:response.cookies.nba-4.expires", "STRING:response.cookies.nba-4.path", "STRING:response.cookies.nba-4.domain" }) public void setValue(final String name, final String value) { results.put(name, value); } public Map getResults() { return results; } @SuppressWarnings({"unused"}) // Used via reflection @Field({ "BYTESCLF:response.body.bytes", "TIME.DAY:request.receive.time.day", "TIME.HOUR:request.receive.time.hour", "TIME.SECOND:request.receive.time.second", "TIME.DAY:request.receive.time.day_utc", "TIME.HOUR:request.receive.time.hour_utc", "TIME.SECOND:request.receive.time.second_utc", "TIME.EPOCH:request.receive.time.epoch", }) public void setValueLong(final String name, final Long value) { longResults.put(name, value); } public Map getLongResults() { return longResults; } } private static final String LOG_FORMAT = "%h %a %A %l %u %t \"%r\" " + "%>s %b %p \"%q\" \"%{Referer}i\" %D \"%{User-agent}i\" " + "\"%{Cookie}i\" " + "\"%{Set-Cookie}o\" " + "\"%{If-None-Match}i\" \"%{Etag}o\""; private static final String COOKIES_LINE = "127.0.0.1 127.0.0.1 127.0.0.1 - - [31/Dec/2012:23:00:44 -0700] \"GET /index.php HTTP/1.1\" " + "200 - 80 \"\" \"-\" 80991 \"Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0\" " + "\"jquery-ui-theme=Eggplant; Apache=127.0.0.1.1351111543699529\" " + "\"" + "NBA-0=, " + "NBA-1=1111, " + "NBA-2=2222; expires=Wed, 01-Jan-2020 00:00:12 GMT, " + "NBA-3=3333; expires=Wed, 01-Jan-2020 00:00:13 GMT; path=/, " + "NBA-4=4444; expires=Wed, 01-Jan-2020 00:00:14 GMT; path=/; domain=.basj.es" + "\" \"-\" \"-\""; // ---------------------------- @Test void testEmptyRecordPossibles() { Parser parser = new HttpdLoglineParser<>(EmptyTestRecord.class, LOG_FORMAT); List possibles = parser.getPossiblePaths(); for (String possible : possibles) { System.out.println(possible); } } // --------------- @Test void testRecordPossibles() { Parser parser = new HttpdLoglineParser<>(TestRecord.class, LOG_FORMAT); List possibles = parser.getPossiblePaths(); for (String possible : possibles) { System.out.println(possible); } } // --------------- private void check(String expect, Map results, String parameter) { assertEquals(expect, results.get(parameter)); } @Test void cookiesTest() throws Exception { Parser parser = new HttpdLoglineParser<>(TestRecord.class, LOG_FORMAT); TestRecord record = new TestRecord(); parser.parse(record, COOKIES_LINE); // --------------- Map results = record.getResults(); Map longResults = record.getLongResults(); // System.out.println(results.toString()); assertEquals(null, results.get("QUERYSTRING:request.firstline.uri.query.foo")); assertEquals("127.0.0.1", results.get("IP:connection.client.ip")); assertEquals(null, results.get("NUMBER:connection.client.logname")); assertEquals(null, results.get("STRING:connection.client.user")); assertEquals("31/Dec/2012:23:00:44 -0700", results.get("TIME.STAMP:request.receive.time")); assertEquals("1357020044000", results.get("TIME.EPOCH:request.receive.time.epoch")); assertEquals(Long.valueOf(1357020044000L), longResults.get("TIME.EPOCH:request.receive.time.epoch")); assertEquals("2012", results.get("TIME.YEAR:request.receive.time.year")); assertEquals("12", results.get("TIME.MONTH:request.receive.time.month")); assertEquals("December", results.get("TIME.MONTHNAME:request.receive.time.monthname")); assertEquals("31", results.get("TIME.DAY:request.receive.time.day")); assertEquals(Long.valueOf(31), longResults.get("TIME.DAY:request.receive.time.day")); assertEquals("23", results.get("TIME.HOUR:request.receive.time.hour")); assertEquals(Long.valueOf(23), longResults.get("TIME.HOUR:request.receive.time.hour")); assertEquals("44", results.get("TIME.SECOND:request.receive.time.second")); assertEquals(Long.valueOf(44), longResults.get("TIME.SECOND:request.receive.time.second")); assertEquals("2013", results.get("TIME.YEAR:request.receive.time.year_utc")); assertEquals("1", results.get("TIME.MONTH:request.receive.time.month_utc")); assertEquals("January", results.get("TIME.MONTHNAME:request.receive.time.monthname_utc")); assertEquals("1", results.get("TIME.DAY:request.receive.time.day_utc")); assertEquals(Long.valueOf(1), longResults.get("TIME.DAY:request.receive.time.day_utc")); assertEquals("6", results.get("TIME.HOUR:request.receive.time.hour_utc")); assertEquals(Long.valueOf(6), longResults.get("TIME.HOUR:request.receive.time.hour_utc")); assertEquals("44", results.get("TIME.SECOND:request.receive.time.second_utc")); assertEquals(Long.valueOf(44), longResults.get("TIME.SECOND:request.receive.time.second_utc")); assertEquals("/index.php", results.get("HTTP.URI:request.firstline.uri")); assertEquals("200", results.get("STRING:request.status.last")); // The "-" value means "Not specified" which is mapped to the setter being called // with a 'null' value intending to say "We know it is not there". assertTrue(results.containsKey("BYTESCLF:response.body.bytes")); assertEquals(null, results.get("BYTESCLF:response.body.bytes")); assertTrue(longResults.containsKey("BYTESCLF:response.body.bytes")); assertEquals(null, longResults.get("BYTESCLF:response.body.bytes")); assertEquals(null, results.get("HTTP.URI:request.referer")); assertEquals("Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0", results.get("HTTP.USERAGENT:request.user-agent")); assertEquals("80991", results.get("MICROSECONDS:response.server.processing.time")); assertEquals(null, results.get("HTTP.HEADER:response.header.etag")); assertEquals("Eggplant", results.get("HTTP.COOKIE:request.cookies.jquery-ui-theme")); assertEquals("127.0.0.1.1351111543699529", results.get("HTTP.COOKIE:request.cookies.apache")); assertEquals("NBA-0=, " + "NBA-1=1111, " + "NBA-2=2222; expires=Wed, 01-Jan-2020 00:00:12 GMT, " + "NBA-3=3333; expires=Wed, 01-Jan-2020 00:00:13 GMT; path=/, " + "NBA-4=4444; expires=Wed, 01-Jan-2020 00:00:14 GMT; path=/; domain=.basj.es", results.get("HTTP.SETCOOKIES:response.cookies")); assertEquals("NBA-4=4444; expires=Wed, 01-Jan-2020 00:00:14 GMT; path=/; domain=.basj.es", results.get("HTTP.SETCOOKIE:response.cookies.nba-4")); assertEquals("4444", results.get("STRING:response.cookies.nba-4.value")); // The returned value may be off by 1 or 2 seconds due to rounding. assertEquals(1577836814D, Double.parseDouble(results.get("STRING:response.cookies.nba-4.expires")), 2D); assertEquals("/", results.get("STRING:response.cookies.nba-4.path")); assertEquals(".basj.es", results.get("STRING:response.cookies.nba-4.domain")); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/EdgeCasesTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; class EdgeCasesTest { @Test void testInvalidFirstLine() { String logFormat = "%a %{Host}i %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %{Content-length}i %P %A"; String testLine = "1.2.3.4 - - [03/Apr/2017:03:27:28 -0600] \"\\x16\\x03\\x01\" 404 419 \"-\" \"-\" - 115052 5.6.7.8"; DissectorTester.create() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(testLine) .expect("IP:connection.client.ip", "1.2.3.4") .expect("IP:connection.server.ip", "5.6.7.8") .expect("TIME.EPOCH:request.receive.time.last.epoch", 1491211648000L) .expect("STRING:connection.client.user", (String)null) // Is present AND is null .expect("TIME.STAMP:request.receive.time.last", "03/Apr/2017:03:27:28 -0600") .expect("TIME.DATE:request.receive.time.last.date", "2017-04-03") .expect("TIME.TIME:request.receive.time.last.time", "03:27:28") .expect("NUMBER:connection.server.child.processid", "115052") .expect("BYTES:response.bytes", "419") .expect("STRING:request.status.last", "404") .expectNull("HTTP.USERAGENT:request.user-agent") .expectNull("HTTP.HEADER:request.header.host") .expectNull("HTTP.HEADER:request.header.content-length") .expectNull("HTTP.URI:request.referer") // This thing should be unparsable .expect("HTTP.FIRSTLINE:request.firstline", "\u0016\u0003\u0001") .expectAbsentString("HTTP.METHOD:request.firstline.method") .expectAbsentString("HTTP.URI:request.firstline.uri") .expectAbsentString("HTTP.PROTOCOL:request.firstline.protocol") .checkExpectations(); } void checkBadUri(String logLine, String expectedUri) { String logFormat = "common"; assertDoesNotThrow(() -> { DissectorTester.create() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .expect("HTTP.URI:request.firstline.uri", expectedUri) .expectAbsentString("HTTP.HOST:request.firstline.uri.host") .expectAbsentString("HTTP.PATH:request.firstline.uri.path") .expectAbsentString("HTTP.PORT:request.firstline.uri.port") .expectAbsentString("HTTP.PROTOCOL:request.firstline.uri.protocol") .expectAbsentString("HTTP.QUERYSTRING:request.firstline.uri.query") .expectAbsentString("HTTP.REF:request.firstline.uri.ref") .expectAbsentString("HTTP.USERINFO:request.firstline.uri.userinfo") .printAllPossibleValues(); }); } @Test void testBadUri() { checkBadUri( "10.10.10.10 - - [28/Feb/2023:16:48:52 +0800] \"GET :@bxss.me::80/rpb.png HTTP/1.1\" 400 1160", ":@bxss.me::80/rpb.png"); checkBadUri( "10.10.10.10 - - [28/Feb/2023:16:48:51 +0800] \"GET @bxss.me::80/rpb.png HTTP/1.1\" 400 1160", "@bxss.me::80/rpb.png"); checkBadUri( "10.10.10.10 - - [28/Feb/2023:16:48:51 +0800] \"GET :@bxss.me/rpb.png HTTP/1.1\" 400 1160", ":@bxss.me/rpb.png"); } @Test void checkErrorLogging(){ HttpdLogFormatDissector dissector = new HttpdLogFormatDissector(); dissector // Apache format .addLogFormat("%t") .addMultipleLogFormats("%a\n%b\n%c") .addLogFormat("%b") // Already have this one // Nginx format .addLogFormat("$remote_addr") .addMultipleLogFormats("$time_local\n$body_bytes_sent\n$status") .addLogFormat("$body_bytes_sent") // Already have this one // Unable to determine .addLogFormat("blup"); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/JettyLogFormatParserTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; class JettyLogFormatParserTest { // ------------------------------------------ public static class TestRecord { private final Map results = new HashMap<>(32); @SuppressWarnings("UnusedDeclaration") @Field({ "IP:connection.client.host", "NUMBER:connection.client.logname", "STRING:connection.client.user", "TIME.STAMP:request.receive.time", "TIME.DAY:request.receive.time.day", "HTTP.FIRSTLINE:request.firstline", "STRING:request.status.last", "BYTES:response.body.bytes", "HTTP.URI:request.referer", "HTTP.USERAGENT:request.user-agent", "MICROSECONDS:response.server.processing.time" }) public void setValue(final String name, final String value) { results.put(name, value); } public Map getResults() { return results; } } // ------------------------------------------ @Test void buggyJettyLogline() throws Exception { // In Jetty // - an extra space is included if the useragent is absent (the >"-" < near the end). // - two extra spaces are included if the user field is absent ( " - " instead of "-" ) String[] lines = { "0.0.0.0 - x [24/Jul/2016:07:08:31 +0000] \"GET http://[:1]/foo HTTP/1.1\" 400 0 \"http://other.site\" \"-\" 8", "0.0.0.0 - - [24/Jul/2016:07:08:31 +0000] \"GET http://[:1]/foo HTTP/1.1\" 400 0 \"http://other.site\" \"-\" 8", "0.0.0.0 - x [24/Jul/2016:07:08:31 +0000] \"GET http://[:1]/foo HTTP/1.1\" 400 0 \"http://other.site\" \"Mozilla/5.0 (dummy)\" 8", "0.0.0.0 - - [24/Jul/2016:07:08:31 +0000] \"GET http://[:1]/foo HTTP/1.1\" 400 0 \"http://other.site\" \"Mozilla/5.0 (dummy)\" 8", }; Parser parser = new HttpdLoglineParser<>(TestRecord.class, "ENABLE JETTY FIX\n"+ "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" ); for (String line:lines) { TestRecord record = new TestRecord(); parser.parse(record, line); Map results = record.getResults(); assertEquals("0.0.0.0", results.get("IP:connection.client.host")); assertEquals(null, results.get("NUMBER:connection.client.logname")); String user = results.get("STRING:connection.client.user"); if (user!=null) { assertEquals("x", user); } assertEquals("24/Jul/2016:07:08:31 +0000", results.get("TIME.STAMP:request.receive.time")); assertEquals("24", results.get("TIME.DAY:request.receive.time.day")); assertEquals("GET http://[:1]/foo HTTP/1.1", results.get("HTTP.FIRSTLINE:request.firstline")); assertEquals("400", results.get("STRING:request.status.last")); assertEquals("0", results.get("BYTES:response.body.bytes")); assertEquals("http://other.site", results.get("HTTP.URI:request.referer")); String useragent = results.get("HTTP.USERAGENT:request.user-agent"); if (useragent!=null) { assertEquals("Mozilla/5.0 (dummy)", useragent); } assertEquals("8", results.get("MICROSECONDS:response.server.processing.time")); } } // ----------------------------------------- } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/JsonLogFormatTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import org.junit.jupiter.api.Test; // CHECKSTYLE.OFF: LineLength class JsonLogFormatTest { // As seen here: http://mail-archives.apache.org/mod_mbox/kafka-users/201408.mbox/%3C1407447350019.7022@roomkey.com%3E // LogFormat "{\"@timestamp\":\"%{%Y-%m-%dT%H:%M:%S%z}t\",\"mod_proxy\":{\"x-forwarded-for\":\"%{X-Forwarded-For}i\"},\"mod_headers\":{\"referer\":\"%{Referer}i\",\"user-agent\":\"%{User-Agent}i\",\"host\":\"%{Host}i\"},\"mod_log\":{\"server_name\":\"%V\",\"remote_logname\":\"%l\",\"remote_user\":\"%u\",\"first_request\":\"%r\",\"last_request_status\":\"%>s\",\"response_size_bytes\":%B,\"duration_usec\":%D,\"@version\":1 }" logstash_json private static final String LOGFORMAT = "{\"@timestamp\":\"%{%Y-%m-%dT%H:%M:%S %z}t\",\"mod_proxy\":{\"x-forwarded-for\":\"%{X-Forwarded-For}i\"},\"mod_headers\":{\"referer\":\"%{Referer}i\",\"user-agent\":\"%{User-Agent}i\",\"host\":\"%{Host}i\"},\"mod_log\":{\"server_name\":\"%V\",\"remote_logname\":\"%l\",\"remote_user\":\"%u\",\"first_request\":\"%r\",\"last_request_status\":\"%>s\",\"response_size_bytes\":%B,\"duration_usec\":%D,\"@version\":1 }"; private static final String[] LOGLINES = { "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"-\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET / HTTP/1.1\",\"last_request_status\":\"403\",\"response_size_bytes\":4897,\"duration_usec\":909,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /noindex/css/bootstrap.min.css HTTP/1.1\",\"last_request_status\":\"200\",\"response_size_bytes\":19341,\"duration_usec\":657,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /noindex/css/open-sans.css HTTP/1.1\",\"last_request_status\":\"200\",\"response_size_bytes\":5081,\"duration_usec\":680,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /images/apache_pb.gif HTTP/1.1\",\"last_request_status\":\"200\",\"response_size_bytes\":2326,\"duration_usec\":728,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /images/poweredby.png HTTP/1.1\",\"last_request_status\":\"200\",\"response_size_bytes\":3956,\"duration_usec\":498,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/noindex/css/open-sans.css\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /noindex/css/fonts/Light/OpenSans-Light.woff HTTP/1.1\",\"last_request_status\":\"404\",\"response_size_bytes\":241,\"duration_usec\":147,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/noindex/css/open-sans.css\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /noindex/css/fonts/Bold/OpenSans-Bold.woff HTTP/1.1\",\"last_request_status\":\"404\",\"response_size_bytes\":239,\"duration_usec\":536,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/noindex/css/open-sans.css\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /noindex/css/fonts/Bold/OpenSans-Bold.ttf HTTP/1.1\",\"last_request_status\":\"404\",\"response_size_bytes\":238,\"duration_usec\":347,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/noindex/css/open-sans.css\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /noindex/css/fonts/Light/OpenSans-Light.ttf HTTP/1.1\",\"last_request_status\":\"404\",\"response_size_bytes\":240,\"duration_usec\":268,\"@version\":1 }", "{\"@timestamp\":\"2015-11-25T15:24:45 +0100\",\"mod_proxy\":{\"x-forwarded-for\":\"-\"},\"mod_headers\":{\"referer\":\"http://localhost/\",\"user-agent\":\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36\",\"host\":\"localhost\"},\"mod_log\":{\"server_name\":\"localhost\",\"remote_logname\":\"-\",\"remote_user\":\"-\",\"first_request\":\"GET /favicon.ico HTTP/1.1\",\"last_request_status\":\"404\",\"response_size_bytes\":209,\"duration_usec\":342,\"@version\":1 }", }; @Test void testBasicParsing() { Parser parser = new HttpdLoglineParser<>(TestRecord.class, LOGFORMAT); DissectorTester tester = DissectorTester.create() .withParser(parser) .verbose(); for (String logline: LOGLINES){ tester.withInput(logline); } tester.expectValuePresent("TIME.LOCALIZEDSTRING:request.receive.time") .expectValuePresent("STRING:connection.server.name") .expectValuePresent("NUMBER:connection.client.logname") .expectNull("STRING:connection.client.user") .expectValuePresent("HTTP.HEADER:request.header.x-forwarded-for") .expectValuePresent("HTTP.URI:request.referer") .expectValuePresent("HTTP.USERAGENT:request.user-agent") .expectValuePresent("HTTP.HEADER:request.header.host") .expectValuePresent("HTTP.FIRSTLINE:request.firstline") .expectValuePresent("HTTP.METHOD:request.firstline.method") .expectValuePresent("HTTP.URI:request.firstline.uri") .expectValuePresent("HTTP.PROTOCOL:request.firstline.protocol") .expectValuePresent("HTTP.PROTOCOL.VERSION:request.firstline.protocol.version") .expectValuePresent("STRING:request.status.last") .expectValuePresent("BYTES:response.body.bytes") .expectValuePresent("MICROSECONDS:response.server.processing.time") .expectAbsentString("HTTP.QUERYSTRING:request.firstline.uri.query") .expectValuePresent("HTTP.PATH:request.firstline.uri.path") .expectAbsentString("HTTP.REF:request.firstline.uri.ref"); for (String path: parser.getPossiblePaths()){ tester.expectPossible(path); } tester.checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/MultiLineHttpdLogParserTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Field; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import org.junit.jupiter.api.Test; import java.util.HashMap; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; class MultiLineHttpdLogParserTest { // ------------------------------------------ public static class TestRecord { private final Map results = new HashMap<>(32); @SuppressWarnings("UnusedDeclaration") @Field({ "IP:connection.client.host", "TIME.STAMP:request.receive.time", "TIME.SECOND:request.receive.time.second", "STRING:request.status.last", "BYTESCLF:response.body.bytes", "HTTP.URI:request.firstline.uri", "HTTP.URI:request.referer", "HTTP.USERAGENT:request.user-agent"}) public void setValue(final String name, final String value) { results.put(name, value); } public Map getResults() { return results; } } // ------------------------------------------ /** * Test of initialize method, of class ApacheHttpdLogParser. */ @Test void fullTest1() throws Exception { String logFormat = LOG_FORMAT_1 + '\n' + '\n' + LOG_FORMAT_2 + '\n' + '\n'; Parser parser = new HttpdLoglineParser<>(TestRecord.class, logFormat); validateLine1(parser); validateLine1(parser); validateLine2(parser); validateLine2(parser); validateLine1(parser); validateLine1(parser); validateLine2(parser); validateLine2(parser); validateLine1(parser); validateLine1(parser); validateLine2(parser); validateLine2(parser); } private static final String LOG_FORMAT_1 = "%h %t \"%r\" %>s %b \"%{Referer}i\""; private static final String LINE_1 = "127.0.0.1 [31/Dec/2012:23:49:41 +0100] " + "\"GET /foo HTTP/1.1\" 200 " + "1213 \"http://localhost/index.php?mies=wim\""; private void validateLine1(Parser parser) throws InvalidDissectorException, MissingDissectorsException, DissectionFailure { TestRecord record = new TestRecord(); parser.parse(record, LINE_1); Map results = record.getResults(); assertEquals("127.0.0.1", results.get("IP:connection.client.host")); assertEquals("31/Dec/2012:23:49:41 +0100", results.get("TIME.STAMP:request.receive.time")); assertEquals("/foo", results.get("HTTP.URI:request.firstline.uri")); assertEquals("200", results.get("STRING:request.status.last")); assertEquals("1213", results.get("BYTESCLF:response.body.bytes")); assertEquals("http://localhost/index.php?mies=wim", results.get("HTTP.URI:request.referer")); assertEquals(null, results.get("HTTP.USERAGENT:request.user-agent")); } private static final String LOG_FORMAT_2 = "%h %t \"%r\" %>s \"%{User-Agent}i\""; private static final String LINE_2 = "127.0.0.2 [31/Dec/2012:23:49:42 +0100] " + "\"GET /foo HTTP/1.1\" 404 " + "\"Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0\""; private void validateLine2(Parser parser) throws InvalidDissectorException, MissingDissectorsException, DissectionFailure { TestRecord record = new TestRecord(); parser.parse(record, LINE_2); Map results = record.getResults(); assertEquals("127.0.0.2", results.get("IP:connection.client.host")); assertEquals("31/Dec/2012:23:49:42 +0100", results.get("TIME.STAMP:request.receive.time")); assertEquals("/foo", results.get("HTTP.URI:request.firstline.uri")); assertEquals("404", results.get("STRING:request.status.last")); assertEquals(null, results.get("BYTESCLF:response.body.bytes")); assertEquals(null, results.get("HTTP.URI:request.referer")); assertEquals("Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0", results.get("HTTP.USERAGENT:request.user-agent")); } // ------------------------------------------ } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/NginxLogFormatJsonTest.java ================================================ /* * Apache HTTPD logparsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import org.junit.jupiter.api.Test; class NginxLogFormatJsonTest { @Test void testJsonFormat() { String logFormat = "{ " + "\"message\":\"$request_uri\"," + "\"client\": \"$remote_addr\"," + "\"auth\": \"$remote_user\", " + "\"bytes\": \"$body_bytes_sent\", " + "\"time_in_sec\": \"$request_time\", " + "\"response\": \"$status\", " + "\"verb\":\"$request_method\"," + "\"referrer\": \"$http_referer\", " + "\"site\":\"$http_host\"," + "\"httpversion\":\"$server_protocol\"," + "\"logtype\":\"accesslog\"," + "\"agent\": \"$http_user_agent\" }"; String logLine = "{ " + "\"message\":\"/one/two/tool.git/info/refs?service=upload-pack\"," + "\"client\": \"10.11.12.13\"," + "\"auth\": \"-\", " + "\"bytes\": \"178\", " + "\"time_in_sec\": \"0.000\", " + "\"response\": \"301\", " + "\"verb\":\"GET\"," + "\"referrer\": \"-\", " + "\"site\":\"some.thing.example.com\"," + "\"httpversion\":\"HTTP/1.1\"," + "\"logtype\":\"accesslog\"," + "\"agent\": \"git/1.9.5.msysgit.0\" }"; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .printPossible() .printAllPossibleValues(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/NginxLogFormatTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; // CHECKSTYLE.OFF: LineLength public class NginxLogFormatTest { private static final Logger LOG = LoggerFactory.getLogger(NginxLogFormatTest.class); @Test void testBasicLogFormat() { // From: http://articles.slicehost.com/2010/8/27/customizing-nginx-web-logs String logFormat = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""; String logLine = "123.65.150.10 - - [23/Aug/2010:03:50:59 +0000] \"POST /wordpress3/wp-admin/admin-ajax.php HTTP/1.1\" 200 2 \"http://www.example.com/wordpress3/wp-admin/post-new.php\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.25 Safari/534.3\""; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .printPossible() .printAllPossibleValues(); } @Test void testBasicLogFormatDissector() { // From: http://articles.slicehost.com/2010/8/27/customizing-nginx-web-logs String logFormat = "combined"; String logLine = "123.65.150.10 - - [23/Aug/2010:03:50:59 +0000] \"POST /wordpress3/wp-admin/admin-ajax.php HTTP/1.1\" 200 2 \"http://www.example.com/wordpress3/wp-admin/post-new.php\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.25 Safari/534.3\""; HttpdLoglineParser parser = new HttpdLoglineParser<>(TestRecord.class, "$msec"); parser.dropDissector(HttpdLogFormatDissector.class); NginxHttpdLogFormatDissector dissector = new NginxHttpdLogFormatDissector(); dissector.setLogFormat(logFormat); parser.addDissector(dissector); DissectorTester.create() .verbose() .withParser(parser) .withInput(logLine) .printPossible() .printAllPossibleValues(); } @Test void testBasicLogFormatWithUnknownField() { // $remote_user_age is fake and doesn't exist. String logFormat = "$foobar $remote_user_age $remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""; String logLine = "something 42 123.65.150.10 - - [23/Aug/2010:03:50:59 +0000] \"POST /wordpress3/wp-admin/admin-ajax.php HTTP/1.1\" 200 2 \"http://www.example.com/wordpress3/wp-admin/post-new.php\" \"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.25 Safari/534.3\""; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .expect("UNKNOWN_NGINX_VARIABLE:nginx.unknown.foobar", "something") .expect("UNKNOWN_NGINX_VARIABLE:nginx.unknown.remote_user_age", "42") .checkExpectations() .printPossible() .printAllPossibleValues(); } @Test void testCompareApacheAndNginxOutput() throws NoSuchMethodException, InvalidDissectorException, MissingDissectorsException, DissectionFailure { String logFormatNginx = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""; // combined format except the logname was removed. String logFormatApache = "%h - %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""; String logLine = "1.2.3.4 - - [23/Aug/2010:03:50:59 +0000] \"POST /foo.html?aap&noot=mies HTTP/1.1\" 200 2 \"http://www.example.com/bar.html?wim&zus=jet\" \"Niels Basjes/1.0\""; Parser apacheParser = new HttpdLoglineParser<>(TestRecord.class, logFormatApache); String[] fieldsArray = { "HTTP.URI:request.referer", "HTTP.PROTOCOL:request.referer.protocol", "HTTP.USERINFO:request.referer.userinfo", "HTTP.HOST:request.referer.host", "HTTP.PORT:request.referer.port", "HTTP.PATH:request.referer.path", "HTTP.QUERYSTRING:request.referer.query", "STRING:request.referer.query.*", "HTTP.REF:request.referer.ref", "TIME.STAMP:request.receive.time", "TIME.DAY:request.receive.time.day", "TIME.MONTHNAME:request.receive.time.monthname", "TIME.MONTH:request.receive.time.month", "TIME.WEEK:request.receive.time.weekofweekyear", "TIME.YEAR:request.receive.time.weekyear", "TIME.YEAR:request.receive.time.year", "TIME.HOUR:request.receive.time.hour", "TIME.MINUTE:request.receive.time.minute", "TIME.SECOND:request.receive.time.second", "TIME.MILLISECOND:request.receive.time.millisecond", "TIME.DATE:request.receive.time.date", "TIME.TIME:request.receive.time.time", "TIME.ZONE:request.receive.time.timezone", "TIME.EPOCH:request.receive.time.epoch", "TIME.DAY:request.receive.time.day_utc", "TIME.MONTHNAME:request.receive.time.monthname_utc", "TIME.MONTH:request.receive.time.month_utc", "TIME.WEEK:request.receive.time.weekofweekyear_utc", "TIME.YEAR:request.receive.time.weekyear_utc", "TIME.YEAR:request.receive.time.year_utc", "TIME.HOUR:request.receive.time.hour_utc", "TIME.MINUTE:request.receive.time.minute_utc", "TIME.SECOND:request.receive.time.second_utc", "TIME.MILLISECOND:request.receive.time.millisecond_utc", "TIME.DATE:request.receive.time.date_utc", "TIME.TIME:request.receive.time.time_utc", "BYTESCLF:response.body.bytes", "BYTES:response.body.bytes", "STRING:request.status.last", "HTTP.USERAGENT:request.user-agent", "HTTP.FIRSTLINE:request.firstline", "HTTP.METHOD:request.firstline.method", "HTTP.URI:request.firstline.uri", "HTTP.PROTOCOL:request.firstline.uri.protocol", "HTTP.USERINFO:request.firstline.uri.userinfo", "HTTP.HOST:request.firstline.uri.host", "HTTP.PORT:request.firstline.uri.port", "HTTP.PATH:request.firstline.uri.path", "HTTP.QUERYSTRING:request.firstline.uri.query", "STRING:request.firstline.uri.query.*", "HTTP.REF:request.firstline.uri.ref", "HTTP.PROTOCOL_VERSION:request.firstline.protocol", "HTTP.PROTOCOL:request.firstline.protocol", "HTTP.PROTOCOL.VERSION:request.firstline.protocol.version", "IP:connection.client.host" }; List fields = Arrays.asList(fieldsArray); // apacheParser.getPossiblePaths(); ArrayList checkFields = new ArrayList<>(fields.size() + 10); String[] parameterNames = {"aap", "noot", "mies", "wim", "zus", "jet" }; for (String field: fields) { if (field.endsWith(".*")){ String fieldHead = field.substring(0, field.length()-1); for (String parameterName: parameterNames){ checkFields.add(fieldHead + parameterName); } } else { checkFields.add(field); } } Parser nginxParser = new HttpdLoglineParser<>(TestRecord.class, logFormatNginx); for (String field: checkFields) { apacheParser.addParseTarget(TestRecord.class.getMethod("setStringValue", String.class, String.class), field); nginxParser.addParseTarget(TestRecord.class.getMethod("setStringValue", String.class, String.class), field); } LOG.info("Running Apache parser"); TestRecord apacheRecord = apacheParser.parse(logLine); LOG.info("Running Nginx parser"); TestRecord nginxRecord = nginxParser.parse(logLine); for (String field: checkFields) { boolean apacheHasValue = apacheRecord.hasStringValue(field); boolean nginxHasValue = nginxRecord.hasStringValue(field); assertEquals(apacheHasValue, nginxHasValue, "Apache and Nginx values for field " + field + " are different."); if (apacheRecord.hasStringValue(field)) { String apacheValue = apacheRecord.getStringValue(field); String nginxValue = nginxRecord.getStringValue(field); assertEquals(apacheValue, nginxValue, "Apache and Nginx values for field " + field + " are different."); } } } @Test void testFullTestAllFields() { String logFormat = "# \"$status\" " + "# \"$time_iso8601\" " + "# \"$time_local\" " + "# \"$arg_name\" " + "# \"$args\" " + "# \"$query_string\" " + "# \"$binary_remote_addr\" " + "# \"$body_bytes_sent\" " + "# \"$bytes_sent\" " + "# \"$connection\" " + "# \"$connection_requests\" " + "# \"$content_length\" " + "# \"$content_type\" " + "# \"$cookie_name\" " + "# \"$document_root\" " + "# \"$host\" " + "# \"$hostname\" " + "# \"$http_name\" " + "# \"$https\" " + "# \"$is_args\" " + "# \"$limit_rate\" " + "# \"$msec\" " + "# \"$nginx_version\" " + "# \"$pid\" " + "# \"$pipe\" " + "# \"$proxy_protocol_addr\" " + "# \"$realpath_root\" " + "# \"$remote_addr\" " + "# \"$remote_port\" " + "# \"$remote_user\" " + "# \"$request\" " + "# \"$request_body\" " + "# \"$request_body_file\" " + "# \"$request_completion\" " + "# \"$request_filename\" " + "# \"$request_length\" " + "# \"$request_method\" " + "# \"$request_time\" " + "# \"$request_uri\" " + "# \"$scheme\" " + "# \"$sent_http_etag\" " + "# \"$sent_http_last_modified\" " + "# \"$server_addr\" " + "# \"$server_name\" " + "# \"$server_port\" " + "# \"$server_protocol\" " + "# \"$tcpinfo_rtt\" " + "# \"$tcpinfo_rttvar\" " + "# \"$tcpinfo_snd_cwnd\" " + "# \"$tcpinfo_rcv_space\" " + "# \"$uri\" " + "# \"$document_uri\" " + "# \"$http_user_agent\" " + "# \"$http_referer\" " + "#"; String logLine = /* $status */ "# \"200\" " + /* $time_iso8601 */ "# \"2017-01-03T15:56:36+01:00\" " + /* $time_local */ "# \"03/Jan/2017:15:56:36 +0100\" " + /* $arg_name */ "# \"-\" " + /* $args */ "# \"aap&noot=&mies=wim\" " + /* $query_string */ "# \"aap&noot=&mies=wim\" " + /* $binary_remote_addr */ "# \"\\x7F\\x00\\x00\\x01\" " + /* $body_bytes_sent */ "# \"436\" " + /* $bytes_sent */ "# \"694\" " + /* $connection */ "# \"5\" " + /* $connection_requests */ "# \"4\" " + /* $content_length */ "# \"-\" " + /* $content_type */ "# \"-\" " + /* $cookie_name */ "# \"-\" " + /* $document_root */ "# \"/var/www/html\" " + /* $host */ "# \"localhost\" " + /* $hostname */ "# \"hackbox\" " + /* $http_name */ "# \"-\" " + /* $https */ "# \"\" " + /* $is_args */ "# \"?\" " + /* $limit_rate */ "# \"0\" " + /* $msec */ "# \"1483455396.639\" " + /* $nginx_version */ "# \"1.10.0\" " + /* $pid */ "# \"5137\" " + /* $pipe */ "# \".\" " + /* $proxy_protocol_addr */ "# \"\" " + /* $realpath_root */ "# \"/var/www/html\" " + /* $remote_addr */ "# \"127.0.0.1\" " + /* $remote_port */ "# \"44448\" " + /* $remote_user */ "# \"-\" " + /* $request */ "# \"GET /?aap&noot=&mies=wim HTTP/1.1\" " + /* $request_body */ "# \"-\" " + /* $request_body_file */ "# \"-\" " + /* $request_completion */ "# \"OK\" " + /* $request_filename */ "# \"/var/www/html/index.html\" " + /* $request_length */ "# \"491\" " + /* $request_method */ "# \"GET\" " + /* $request_time */ "# \"0.000\" " + /* $request_uri */ "# \"/?aap&noot=&mies=wim\" " + /* $scheme */ "# \"http\" " + /* $sent_http_etag */ "# \"W/\\x22586bbb8b-29e\\x22\" " + /* $sent_http_last_modified */ "# \"Tue, 03 Jan 2017 14:56:11 GMT\" " + /* $server_addr */ "# \"127.0.0.1\" " + /* $server_name */ "# \"_\" " + /* $server_port */ "# \"80\" " + /* $server_protocol */ "# \"HTTP/1.1\" " + /* $tcpinfo_rtt */ "# \"52\" " + /* $tcpinfo_rttvar */ "# \"30\" " + /* $tcpinfo_snd_cwnd */ "# \"10\" " + /* $tcpinfo_rcv_space */ "# \"43690\" " + /* $uri */ "# \"/index.html\" " + /* $document_uri */ "# \"/index.html\" " + /* $http_user_agent */ "# \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.100 Safari/537.36\" " + /* $http_referer */ "# \"http://localhost/\" " + "#"; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) // .printPossible() .printAllPossibleValues(); } private static class SingleFieldTestcase { final String logformat; final String logline; final String fieldName; final String expectedValue; SingleFieldTestcase(String logformat, String logline, String fieldName, String expectedValue) { this.logformat = logformat; this.logline = logline; this.fieldName = fieldName; this.expectedValue = expectedValue; } } @Test void validateAllFields() { List fieldsTests = new ArrayList<>(); fieldsTests.add(new SingleFieldTestcase("$status", "200", "STRING:request.status.last", "200")); fieldsTests.add(new SingleFieldTestcase("$time_iso8601", "2017-01-03T15:56:36+01:00", "TIME.ISO8601:request.receive.time", "2017-01-03T15:56:36+01:00")); fieldsTests.add(new SingleFieldTestcase("$time_local", "03/Jan/2017:15:56:36 +0100", "TIME.STAMP:request.receive.time", "03/Jan/2017:15:56:36 +0100")); fieldsTests.add(new SingleFieldTestcase("$time_iso8601", "2017-01-03T15:56:36+01:00", "TIME.EPOCH:request.receive.time.epoch", "1483455396000")); fieldsTests.add(new SingleFieldTestcase("$time_local", "03/Jan/2017:15:56:36 +0100", "TIME.EPOCH:request.receive.time.epoch", "1483455396000")); fieldsTests.add(new SingleFieldTestcase("$msec", "1483455396.639", "TIME.EPOCH:request.receive.time.epoch", "1483455396639")); fieldsTests.add(new SingleFieldTestcase("$remote_addr", "127.0.0.1", "IP:connection.client.host", "127.0.0.1")); fieldsTests.add(new SingleFieldTestcase("$binary_remote_addr", "\\x7F\\x00\\x00\\x01", "IP_BINARY:connection.client.host", "\\x7F\\x00\\x00\\x01")); fieldsTests.add(new SingleFieldTestcase("$binary_remote_addr", "\\x7F\\x00\\x00\\x01", "IP:connection.client.host", "127.0.0.1")); fieldsTests.add(new SingleFieldTestcase("$remote_port", "44448", "PORT:connection.client.port", "44448")); fieldsTests.add(new SingleFieldTestcase("$remote_user", "-", "STRING:connection.client.user", null)); fieldsTests.add(new SingleFieldTestcase("$is_args", "?", "STRING:request.firstline.uri.is_args", "?")); fieldsTests.add(new SingleFieldTestcase("$query_string", "aap&noot=&mies=wim", "HTTP.QUERYSTRING:request.firstline.uri.query", "aap&noot=&mies=wim")); fieldsTests.add(new SingleFieldTestcase("$args", "aap&noot=&mies=wim", "HTTP.QUERYSTRING:request.firstline.uri.query", "aap&noot=&mies=wim")); fieldsTests.add(new SingleFieldTestcase("$args", "aap&noot=&mies=wim", "STRING:request.firstline.uri.query.aap", "")); fieldsTests.add(new SingleFieldTestcase("$args", "aap&noot=&mies=wim", "STRING:request.firstline.uri.query.noot", "")); fieldsTests.add(new SingleFieldTestcase("$args", "aap&noot=&mies=wim", "STRING:request.firstline.uri.query.mies", "wim")); fieldsTests.add(new SingleFieldTestcase("$arg_name", "foo", "STRING:request.firstline.uri.query.name", "foo")); fieldsTests.add(new SingleFieldTestcase("$bytes_sent", "694", "BYTES:response.bytes", "694")); fieldsTests.add(new SingleFieldTestcase("$bytes_received", "694", "BYTES:request.bytes", "694")); fieldsTests.add(new SingleFieldTestcase("$body_bytes_sent", "436", "BYTES:response.body.bytes", "436")); fieldsTests.add(new SingleFieldTestcase("$connection", "5", "NUMBER:connection.serial_number", "5")); fieldsTests.add(new SingleFieldTestcase("$connection_requests", "4", "NUMBER:connection.requestnr", "4")); fieldsTests.add(new SingleFieldTestcase("$https", "", "STRING:connection.https", "")); fieldsTests.add(new SingleFieldTestcase("$content_length", "-", "HTTP.HEADER:request.header.content_length", null)); fieldsTests.add(new SingleFieldTestcase("$content_type", "-", "HTTP.HEADER:request.header.content_type", null)); fieldsTests.add(new SingleFieldTestcase("$cookie_name", "Something", "HTTP.COOKIE:request.cookies.name", "Something")); fieldsTests.add(new SingleFieldTestcase("$document_root", "/var/www/html", "STRING:request.firstline.document_root", "/var/www/html")); fieldsTests.add(new SingleFieldTestcase("$realpath_root", "/var/www/html", "STRING:request.firstline.realpath_root", "/var/www/html")); fieldsTests.add(new SingleFieldTestcase("$host", "localhost", "STRING:connection.server.name", "localhost")); fieldsTests.add(new SingleFieldTestcase("$hostname", "hackbox", "STRING:connection.client.host", "hackbox")); fieldsTests.add(new SingleFieldTestcase("$http_foobar", "Something", "HTTP.HEADER:request.header.foobar", "Something")); fieldsTests.add(new SingleFieldTestcase("$sent_http_foobar", "Something", "HTTP.HEADER:response.header.foobar", "Something")); fieldsTests.add(new SingleFieldTestcase("$sent_trailer_foobar", "Something", "HTTP.TRAILER:response.trailer.foobar", "Something")); fieldsTests.add(new SingleFieldTestcase("$nginx_version", "1.10.0", "STRING:server.nginx.version", "1.10.0")); fieldsTests.add(new SingleFieldTestcase("$pid", "5137", "NUMBER:connection.server.child.processid", "5137")); fieldsTests.add(new SingleFieldTestcase("$pipe", ".", "STRING:connection.nginx.pipe", ".")); fieldsTests.add(new SingleFieldTestcase("$pipe", "p", "STRING:connection.nginx.pipe", "p")); fieldsTests.add(new SingleFieldTestcase("$protocol", "TCP", "STRING:connection.protocol", "TCP")); fieldsTests.add(new SingleFieldTestcase("$proxy_protocol_addr", "1.2.3.4", "IP:connection.client.proxy.host", "1.2.3.4")); fieldsTests.add(new SingleFieldTestcase("$proxy_protocol_port", "1234", "PORT:connection.client.proxy.port", "1234")); fieldsTests.add(new SingleFieldTestcase("$request", "GET /?aap&noot=&mies=wim HTTP/1.1", "HTTP.FIRSTLINE:request.firstline", "GET /?aap&noot=&mies=wim HTTP/1.1")); fieldsTests.add(new SingleFieldTestcase("$request_completion", "OK", "STRING:request.completion", "OK")); fieldsTests.add(new SingleFieldTestcase("$request_filename", "/var/www/html/index.html", "FILENAME:server.filename", "/var/www/html/index.html")); fieldsTests.add(new SingleFieldTestcase("$request_length", "491", "BYTES:request.bytes", "491")); fieldsTests.add(new SingleFieldTestcase("$request_method", "GET", "HTTP.METHOD:request.firstline.method", "GET")); fieldsTests.add(new SingleFieldTestcase("$request_time", "123.456", "SECOND_MILLIS:response.server.processing.time", "123.456")); fieldsTests.add(new SingleFieldTestcase("$request_time", "123.456", "MILLISECONDS:response.server.processing.time", "123456")); fieldsTests.add(new SingleFieldTestcase("$request_time", "123.456", "MICROSECONDS:response.server.processing.time", "123456000")); fieldsTests.add(new SingleFieldTestcase("$request_uri", "/?aap&noot=&mies=wim", "HTTP.URI:request.firstline.uri", "/?aap&noot=&mies=wim")); fieldsTests.add(new SingleFieldTestcase("$scheme", "http", "HTTP.PROTOCOL:request.firstline.uri.protocol", "http")); fieldsTests.add(new SingleFieldTestcase("$sent_http_etag", "W/\\x22586bbb8b-29e\\x22", "HTTP.HEADER:response.header.etag", "W/\\x22586bbb8b-29e\\x22")); fieldsTests.add(new SingleFieldTestcase("$sent_http_last_modified", "Tue, 03 Jan 2017 14:56:11 GMT", "HTTP.HEADER:response.header.last_modified", "Tue, 03 Jan 2017 14:56:11 GMT")); fieldsTests.add(new SingleFieldTestcase("$server_addr", "127.0.0.1", "IP:connection.server.ip", "127.0.0.1")); fieldsTests.add(new SingleFieldTestcase("$server_name", "_", "STRING:connection.server.name", "_")); fieldsTests.add(new SingleFieldTestcase("$server_port", "80", "PORT:connection.server.port", "80")); fieldsTests.add(new SingleFieldTestcase("$server_protocol", "HTTP/1.1", "HTTP.PROTOCOL_VERSION:request.firstline.protocol", "HTTP/1.1")); fieldsTests.add(new SingleFieldTestcase("$server_protocol", "HTTP/1.1", "HTTP.PROTOCOL:request.firstline.protocol", "HTTP")); fieldsTests.add(new SingleFieldTestcase("$server_protocol", "HTTP/1.1", "HTTP.PROTOCOL.VERSION:request.firstline.protocol.version", "1.1")); fieldsTests.add(new SingleFieldTestcase("$tcpinfo_rtt", "52", "MICROSECONDS:connection.tcpinfo.rtt", "52")); fieldsTests.add(new SingleFieldTestcase("$tcpinfo_rttvar", "30", "MICROSECONDS:connection.tcpinfo.rttvar", "30")); fieldsTests.add(new SingleFieldTestcase("$tcpinfo_snd_cwnd", "10", "BYTES:connection.tcpinfo.send.cwnd", "10")); fieldsTests.add(new SingleFieldTestcase("$tcpinfo_rcv_space", "43690", "BYTES:connection.tcpinfo.receive.space", "43690")); fieldsTests.add(new SingleFieldTestcase("$uri", "/index.html", "HTTP.URI:request.firstline.uri.normalized", "/index.html")); fieldsTests.add(new SingleFieldTestcase("$document_uri", "/index.html", "HTTP.URI:request.firstline.uri.normalized", "/index.html")); fieldsTests.add(new SingleFieldTestcase("$http_user_agent", "Mozilla/5.0 (Foo)", "HTTP.USERAGENT:request.user-agent", "Mozilla/5.0 (Foo)")); fieldsTests.add(new SingleFieldTestcase("$http_foo_user_agent", "Mozilla/5.0 (Foo)", "HTTP.HEADER:request.header.foo_user_agent", "Mozilla/5.0 (Foo)")); fieldsTests.add(new SingleFieldTestcase("$http_user_agent_foo", "Mozilla/5.0 (Foo)", "HTTP.HEADER:request.header.user_agent_foo", "Mozilla/5.0 (Foo)")); fieldsTests.add(new SingleFieldTestcase("$http_referer", "http://localhost/", "HTTP.URI:request.referer", "http://localhost/")); // TODO: Check if these are REALLY "not intended for logging" fieldsTests.add(new SingleFieldTestcase("$request_body", "-", "NOT_IMPLEMENTED:nginx_parameter_not_intended_for_logging__request_body", null)); fieldsTests.add(new SingleFieldTestcase("$request_body_file", "-", "NOT_IMPLEMENTED:nginx_parameter_not_intended_for_logging__request_body_file", null)); fieldsTests.add(new SingleFieldTestcase("$limit_rate", "0", "NOT_IMPLEMENTED:nginx_parameter_not_intended_for_logging__limit_rate", "0")); for (SingleFieldTestcase testCase: fieldsTests) { DissectorTester.create() .printSeparator() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, testCase.logformat)) .withInput(testCase.logline) .expect(testCase.fieldName, testCase.expectedValue) .printPossible() .printAllPossibleValues() .checkExpectations(); } } @Test void validateAllFieldsPrefix() { List fieldsTests = new ArrayList<>(); final String useragent = "Mozilla/5.0 (Foo)"; fieldsTests.add(new SingleFieldTestcase("$http_user_agent", useragent, "HTTP.USERAGENT:request.user-agent", useragent)); fieldsTests.add(new SingleFieldTestcase("$http_foo_user_agent", useragent, "HTTP.HEADER:request.header.foo_user_agent", useragent)); fieldsTests.add(new SingleFieldTestcase("$http_user_agent_foo", useragent, "HTTP.HEADER:request.header.user_agent_foo", useragent)); for (SingleFieldTestcase testCase: fieldsTests) { DissectorTester.create() .printSeparator() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, testCase.logformat)) .withInput(testCase.logline) .expect(testCase.fieldName, testCase.expectedValue) .printPossible() .printAllPossibleValues() .checkExpectations(); } } @Test void bugReport60(){ String logFormat = "$the_real_ip - [$the_real_ip] - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" $request_length $request_time [$proxy_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id"; String logLine = "1.2.3.4 - [1.2.3.4] - - [07/Aug/2020:15:50:07 +0800] \"HEAD /ai/search/version HTTP/1.1\" 308 0 \"-\" \"curl/7.29.0\" 100 0.000 [default-ai-search-prod-svc-5009] - - - - bfb9417db656d95bcfdf3e2a7f47b1ec"; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .expect("STRING:connection.client.user", (String)null) .expect("BYTES:request.bytes", "100") .expect("BYTESCLF:request.bytes", "100") .expect("STRING:nginxmodule.kubernetes.req_id", "bfb9417db656d95bcfdf3e2a7f47b1ec") .expect("HTTP.URI:request.referer", (String) null) .expectAbsentString("HTTP.PROTOCOL:request.referer.protocol") .expectAbsentString("HTTP.USERINFO:request.referer.userinfo") .expectAbsentString("HTTP.HOST:request.referer.host") .expectAbsentString("HTTP.PORT:request.referer.port") .expectAbsentString("HTTP.PATH:request.referer.path") .expectAbsentString("HTTP.QUERYSTRING:request.referer.query") .expectAbsentString("STRING:request.referer.query.*") .expectAbsentString("HTTP.REF:request.referer.ref") .expect("SECOND_MILLIS:response.server.processing.time", "0.000") .expect("MILLISECONDS:response.server.processing.time", "0") .expect("MICROSECONDS:response.server.processing.time", "0") .expect("TIME.STAMP:request.receive.time", "07/Aug/2020:15:50:07 +0800") .expect("TIME.DAY:request.receive.time.day", "7") .expect("TIME.MONTHNAME:request.receive.time.monthname", "August") .expect("TIME.MONTH:request.receive.time.month", "8") .expect("TIME.WEEK:request.receive.time.weekofweekyear", "32") .expect("TIME.YEAR:request.receive.time.weekyear", "2020") .expect("TIME.YEAR:request.receive.time.year", "2020") .expect("TIME.HOUR:request.receive.time.hour", "15") .expect("TIME.MINUTE:request.receive.time.minute", "50") .expect("TIME.SECOND:request.receive.time.second", "7") .expect("TIME.MILLISECOND:request.receive.time.millisecond", "0") .expect("TIME.MICROSECOND:request.receive.time.microsecond", "0") .expect("TIME.NANOSECOND:request.receive.time.nanosecond", "0") .expect("TIME.DATE:request.receive.time.date", "2020-08-07") .expect("TIME.TIME:request.receive.time.time", "15:50:07") .expect("TIME.ZONE:request.receive.time.timezone", "+08:00") .expect("TIME.EPOCH:request.receive.time.epoch", "1596786607000") .expect("TIME.DAY:request.receive.time.day_utc", "7") .expect("TIME.MONTHNAME:request.receive.time.monthname_utc", "August") .expect("TIME.MONTH:request.receive.time.month_utc", "8") .expect("TIME.WEEK:request.receive.time.weekofweekyear_utc", "32") .expect("TIME.YEAR:request.receive.time.weekyear_utc", "2020") .expect("TIME.YEAR:request.receive.time.year_utc", "2020") .expect("TIME.HOUR:request.receive.time.hour_utc", "7") .expect("TIME.MINUTE:request.receive.time.minute_utc", "50") .expect("TIME.SECOND:request.receive.time.second_utc", "7") .expect("TIME.MILLISECOND:request.receive.time.millisecond_utc", "0") .expect("TIME.MICROSECOND:request.receive.time.microsecond_utc", "0") .expect("TIME.NANOSECOND:request.receive.time.nanosecond_utc", "0") .expect("TIME.DATE:request.receive.time.date_utc", "2020-08-07") .expect("TIME.TIME:request.receive.time.time_utc", "07:50:07") .expect("STRING:request.status.last", "308") .expect("HTTP.USERAGENT:request.user-agent", "curl/7.29.0") .expect("IP:nginxmodule.kubernetes.the_real_ip", "1.2.3.4") .expect("HTTP.FIRSTLINE:request.firstline", "HEAD /ai/search/version HTTP/1.1") .expect("HTTP.METHOD:request.firstline.method", "HEAD") .expect("HTTP.URI:request.firstline.uri", "/ai/search/version") .expectAbsentString("HTTP.PROTOCOL:request.firstline.uri.protocol") .expectAbsentString("HTTP.USERINFO:request.firstline.uri.userinfo") .expectAbsentString("HTTP.HOST:request.firstline.uri.host") .expectAbsentString("HTTP.PORT:request.firstline.uri.port") .expect("HTTP.PATH:request.firstline.uri.path", "/ai/search/version") .expectAbsentString("HTTP.QUERYSTRING:request.firstline.uri.query") .expectAbsentString("STRING:request.firstline.uri.query.*") .expectAbsentString("HTTP.REF:request.firstline.uri.ref") .expect("HTTP.PROTOCOL_VERSION:request.firstline.protocol", "HTTP/1.1") .expect("HTTP.PROTOCOL:request.firstline.protocol", "HTTP") .expect("HTTP.PROTOCOL.VERSION:request.firstline.protocol.version", "1.1") .expect("BYTES:response.body.bytes", "0") .expect("BYTESCLF:response.body.bytes", 0L) .expect("STRING:nginxmodule.kubernetes.proxy_upstream_name", "default-ai-search-prod-svc-5009") .expect("UPSTREAM_BYTES_LIST:nginxmodule.upstream.response.length", (String)null) .expect("UPSTREAM_STATUS_LIST:nginxmodule.upstream.status", (String)null) .expect("UPSTREAM_SECOND_MILLIS_LIST:nginxmodule.upstream.response.time", (String)null) .expect("UPSTREAM_ADDR_LIST:nginxmodule.upstream.addr", (String)null) .checkExpectations(); } @Test void bugReport227_bad(){ String logFormat = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"-\""; String logLine = "94.232.44.112 - - [28/Feb/2021:03:54:40 +0800] \"x00Cookie: mstshash=Administr\" 400 157 \"-\" \"-\" \"-\""; DissectorTester.create() // .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .expect("IP:connection.client.host", "94.232.44.112") .expect("STRING:connection.client.user", (String)null) .expect("HTTP.FIRSTLINE:request.firstline", "x00Cookie: mstshash=Administr") .expectAbsentString("HTTP.METHOD:request.firstline.method") .expectAbsentString("HTTP.URI:request.firstline.uri") .expectAbsentString("HTTP.PROTOCOL:request.firstline.protocol") .expect("TIME.STAMP:request.receive.time", "28/Feb/2021:03:54:40 +0800") .expect("TIME.DATE:request.receive.time.date", "2021-02-28") .expect("TIME.TIME:request.receive.time.time", "03:54:40") .expect("TIME.ZONE:request.receive.time.timezone", "+08:00") .expect("TIME.YEAR:request.receive.time.year", "2021") .expect("TIME.MONTH:request.receive.time.month", "2") .expect("TIME.DAY:request.receive.time.day", "28") .expect("TIME.HOUR:request.receive.time.hour", "3") .expect("TIME.MINUTE:request.receive.time.minute", "54") .expect("TIME.SECOND:request.receive.time.second", "40") .expect("TIME.EPOCH:request.receive.time.epoch", "1614455680000") .expect("HTTP.URI:request.referer", (String)null) .expect("STRING:request.status.last", "400") .expect("BYTES:response.body.bytes", "157") .expect("HTTP.USERAGENT:request.user-agent", (String)null) .checkExpectations(); } @Test void bugReport227_empty() { String logFormat = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"-\""; String logLine = "207.154.195.167 - - [01/Mar/2021:03:25:25 +0800] \"\" 400 0 \"-\" \"-\" \"-\""; DissectorTester.create() // .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .expect("IP:connection.client.host", "207.154.195.167") .expect("STRING:connection.client.user", (String)null) .expect("HTTP.FIRSTLINE:request.firstline", "") .expectAbsentString("HTTP.METHOD:request.firstline.method") .expectAbsentString("HTTP.URI:request.firstline.uri") .expectAbsentString("HTTP.PROTOCOL:request.firstline.protocol") .expect("TIME.STAMP:request.receive.time", "01/Mar/2021:03:25:25 +0800") .expect("TIME.DATE:request.receive.time.date", "2021-03-01") .expect("TIME.TIME:request.receive.time.time", "03:25:25") .expect("TIME.ZONE:request.receive.time.timezone", "+08:00") .expect("TIME.YEAR:request.receive.time.year", "2021") .expect("TIME.MONTH:request.receive.time.month", "3") .expect("TIME.DAY:request.receive.time.day", "1") .expect("TIME.HOUR:request.receive.time.hour", "3") .expect("TIME.MINUTE:request.receive.time.minute", "25") .expect("TIME.SECOND:request.receive.time.second", "25") .expect("TIME.EPOCH:request.receive.time.epoch", "1614540325000") .expect("HTTP.URI:request.referer", (String)null) .expect("STRING:request.status.last", "400") .expect("BYTES:response.body.bytes", "0") .expect("HTTP.USERAGENT:request.user-agent", (String)null) .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/UtilsTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import org.junit.jupiter.api.Test; import static nl.basjes.parse.httpdlog.Utils.makeHTMLEncodedInert; import static nl.basjes.parse.httpdlog.Utils.resilientUrlDecode; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; class UtilsTest { @Test void testUrlDecoder() { // Normal cases assertEquals(" ", resilientUrlDecode(" ")); assertEquals(" ", resilientUrlDecode(" %20")); assertEquals(" ", resilientUrlDecode("%20 ")); assertEquals(" ", resilientUrlDecode("%20%20")); assertEquals(" ", resilientUrlDecode("%u0020%u0020")); assertEquals(" ", resilientUrlDecode("%20%u0020")); assertEquals(" ", resilientUrlDecode("%u0020%20")); // Deformed characters at the end of the line (desired is they are discarded) assertEquals("x ", resilientUrlDecode("x %2")); assertEquals("x ", resilientUrlDecode("x%20%2")); assertEquals("x 2", resilientUrlDecode("x%u202")); assertEquals("x ", resilientUrlDecode("x%u20")); assertEquals("x", resilientUrlDecode("x%u2")); assertEquals("x", resilientUrlDecode("x%u")); assertEquals("x", resilientUrlDecode("x%")); // Combined test case (7 spaces and a chopped one) assertEquals(" ", resilientUrlDecode("%20 %20%u0020%20 %20%2")); } @Test void testHtmlEncoding() { assertEquals("<", resilientUrlDecode(makeHTMLEncodedInert("<"))); assertEquals(">", resilientUrlDecode(makeHTMLEncodedInert(">"))); assertEquals("€", resilientUrlDecode(makeHTMLEncodedInert("€"))); assertEquals("*#x12345;", makeHTMLEncodedInert("𒍅")); assertEquals("*#xaBcDeF;", makeHTMLEncodedInert("�")); } @Test void testHtmlEncodingFull() { // Normal cases assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert(" "))); assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert(" %20"))); assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert("%20 "))); assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert("%20%20"))); assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert("%u0020%u0020"))); assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert("%20%u0020"))); assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert("%u0020%20"))); // Deformed characters at the end of the line (desired is they are discarded) assertEquals("x ", resilientUrlDecode(makeHTMLEncodedInert("x %2"))); assertEquals("x ", resilientUrlDecode(makeHTMLEncodedInert("x%20%2"))); assertEquals("x 2", resilientUrlDecode(makeHTMLEncodedInert("x%u202"))); assertEquals("x ", resilientUrlDecode(makeHTMLEncodedInert("x%u20"))); assertEquals("x", resilientUrlDecode(makeHTMLEncodedInert("x%u2"))); assertEquals("x", resilientUrlDecode(makeHTMLEncodedInert("x%u"))); assertEquals("x", resilientUrlDecode(makeHTMLEncodedInert("x%"))); // Combined test case (7 spaces and a chopped one) assertEquals(" ", resilientUrlDecode(makeHTMLEncodedInert("%20 %20%u0020%20 %20%2"))); // Normal cases assertEquals(" > ", resilientUrlDecode(makeHTMLEncodedInert(" > "))); assertEquals(" > ", resilientUrlDecode(makeHTMLEncodedInert(" >%20"))); assertEquals(" > ", resilientUrlDecode(makeHTMLEncodedInert("%20> "))); assertEquals(" > ", resilientUrlDecode(makeHTMLEncodedInert("%20>%20"))); assertEquals(" > ", resilientUrlDecode(makeHTMLEncodedInert("%u0020>%u0020"))); assertEquals(" > ", resilientUrlDecode(makeHTMLEncodedInert("%20>%u0020"))); assertEquals(" > ", resilientUrlDecode(makeHTMLEncodedInert("%u0020>%20"))); // Deformed characters at the end of the line (desired is they are discarded) assertEquals(">x ", resilientUrlDecode(makeHTMLEncodedInert(">x %2"))); assertEquals(">x ", resilientUrlDecode(makeHTMLEncodedInert(">x%20%2"))); assertEquals(">x 2", resilientUrlDecode(makeHTMLEncodedInert(">x%u202"))); assertEquals(">x ", resilientUrlDecode(makeHTMLEncodedInert(">x%u20"))); assertEquals(">x", resilientUrlDecode(makeHTMLEncodedInert(">x%u2"))); assertEquals(">x", resilientUrlDecode(makeHTMLEncodedInert(">x%u"))); assertEquals(">x", resilientUrlDecode(makeHTMLEncodedInert(">x%"))); // Normal cases assertEquals(" *foobar; ", resilientUrlDecode(makeHTMLEncodedInert(" &foobar; "))); assertEquals(" *foobar; ", resilientUrlDecode(makeHTMLEncodedInert(" &foobar;%20"))); assertEquals(" *foobar; ", resilientUrlDecode(makeHTMLEncodedInert("%20&foobar; "))); assertEquals(" *foobar; ", resilientUrlDecode(makeHTMLEncodedInert("%20&foobar;%20"))); assertEquals(" *foobar; ", resilientUrlDecode(makeHTMLEncodedInert("%u0020&foobar;%u0020"))); assertEquals(" *foobar; ", resilientUrlDecode(makeHTMLEncodedInert("%20&foobar;%u0020"))); assertEquals(" *foobar; ", resilientUrlDecode(makeHTMLEncodedInert("%u0020&foobar;%20"))); // Deformed characters at the end of the line (desired is they are discarded) assertEquals("*foobar;x ", resilientUrlDecode(makeHTMLEncodedInert("&foobar;x %2"))); assertEquals("*foobar;x ", resilientUrlDecode(makeHTMLEncodedInert("&foobar;x%20%2"))); assertEquals("*foobar;x 2", resilientUrlDecode(makeHTMLEncodedInert("&foobar;x%u202"))); assertEquals("*foobar;x ", resilientUrlDecode(makeHTMLEncodedInert("&foobar;x%u20"))); assertEquals("*foobar;x", resilientUrlDecode(makeHTMLEncodedInert("&foobar;x%u2"))); assertEquals("*foobar;x", resilientUrlDecode(makeHTMLEncodedInert("&foobar;x%u"))); assertEquals("*foobar;x", resilientUrlDecode(makeHTMLEncodedInert("&foobar;x%"))); assertEquals("€", resilientUrlDecode(makeHTMLEncodedInert("€"))); } @Test void testHexToByte() { // Test basic character decoder assertEquals((byte) 0x00, Utils.hexCharsToByte('0', '0')); assertEquals((byte) 0x11, Utils.hexCharsToByte('1', '1')); assertEquals((byte) 0x22, Utils.hexCharsToByte('2', '2')); assertEquals((byte) 0x33, Utils.hexCharsToByte('3', '3')); assertEquals((byte) 0x44, Utils.hexCharsToByte('4', '4')); assertEquals((byte) 0x55, Utils.hexCharsToByte('5', '5')); assertEquals((byte) 0x66, Utils.hexCharsToByte('6', '6')); assertEquals((byte) 0x77, Utils.hexCharsToByte('7', '7')); assertEquals((byte) 0x88, Utils.hexCharsToByte('8', '8')); assertEquals((byte) 0x99, Utils.hexCharsToByte('9', '9')); assertEquals((byte) 0xaa, Utils.hexCharsToByte('a', 'a')); assertEquals((byte) 0xbb, Utils.hexCharsToByte('b', 'b')); assertEquals((byte) 0xcc, Utils.hexCharsToByte('c', 'c')); assertEquals((byte) 0xdd, Utils.hexCharsToByte('d', 'd')); assertEquals((byte) 0xee, Utils.hexCharsToByte('e', 'e')); assertEquals((byte) 0xff, Utils.hexCharsToByte('f', 'f')); assertEquals((byte) 0xAA, Utils.hexCharsToByte('A', 'A')); assertEquals((byte) 0xBB, Utils.hexCharsToByte('B', 'B')); assertEquals((byte) 0xCC, Utils.hexCharsToByte('C', 'C')); assertEquals((byte) 0xDD, Utils.hexCharsToByte('D', 'D')); assertEquals((byte) 0xEE, Utils.hexCharsToByte('E', 'E')); assertEquals((byte) 0xFF, Utils.hexCharsToByte('F', 'F')); } @Test void testHexToByteIllegalLeft() { assertThrows(IllegalArgumentException.class, () -> { Utils.hexCharsToByte('X', '0'); }); } @Test void testHexToByteIllegalRight() { assertThrows(IllegalArgumentException.class, () -> { Utils.hexCharsToByte('0', 'X'); }); } @Test void testApacheLogDecoder() { // Decoding a value assertEquals("bla bla bla", Utils.decodeApacheHTTPDLogValue("bla bla bla")); assertEquals("bla bla bla", Utils.decodeApacheHTTPDLogValue("bla\\x20bla bla")); assertEquals("bla\bbla\nbla\tbla", Utils.decodeApacheHTTPDLogValue("bla\\bbla\\nbla\\tbla")); assertEquals("bla\"bla\nbla\tbla", Utils.decodeApacheHTTPDLogValue("bla\\\"bla\\nbla\\tbla")); assertEquals(new String(new byte[] {(byte)0x0b}), Utils.decodeApacheHTTPDLogValue("\\v")); // Specials assertEquals("\\q", Utils.decodeApacheHTTPDLogValue("\\q")); assertEquals("", Utils.decodeApacheHTTPDLogValue("")); assertNull(Utils.decodeApacheHTTPDLogValue(null)); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/dissectors/TestCookieDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.test.DissectorTester; import org.junit.jupiter.api.Test; class TestCookieDissector { @Test void testRequestCookies() { DissectorTester.create() .withDissector("cookies", new RequestCookieListDissector()) .withInput( "NBA-0; " + "NBA-1=; " + "NBA-2=1234; ") .expect("HTTP.COOKIES:cookies", "NBA-0; NBA-1=; NBA-2=1234; ") .expect("HTTP.COOKIE:cookies.nba-0", "") .expect("HTTP.COOKIE:cookies.nba-1", "") .expect("HTTP.COOKIE:cookies.nba-2", "1234") .checkExpectations(); } @Test void testResponseSetCookies() { DissectorTester.create() .withDissector("cookies", new ResponseSetCookieListDissector()) .withDissector(new ResponseSetCookieDissector()) .withInput( "NBA-0=, " + "NBA-1=1234, " + "NBA-2=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT, " + "NBA-3=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/xx, " + "NBA-4=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/xx; domain=.basj.es, " + "NBA-5=1234; path=/xx; domain=.basj.es, " + "NBA-6=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; domain=.basj.es, " + "NBA-7=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; domain=.basj.es; comment=bla bla bla" ) .expect("HTTP.SETCOOKIES:cookies", "NBA-0=, " + "NBA-1=1234, " + "NBA-2=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT, " + "NBA-3=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/xx, " + "NBA-4=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/xx; domain=.basj.es, " + "NBA-5=1234; path=/xx; domain=.basj.es, " + "NBA-6=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; domain=.basj.es, " + "NBA-7=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; domain=.basj.es; comment=bla bla bla" ) .expect("HTTP.SETCOOKIE:cookies.nba-0", "NBA-0=") .expect("STRING:cookies.nba-0.value", "") .expectAbsentLong("STRING:cookies.nba-0.expires") .expectAbsentString("STRING:cookies.nba-0.path") .expectAbsentString("STRING:cookies.nba-0.domain") .expect("HTTP.SETCOOKIE:cookies.nba-1", "NBA-1=1234") .expect("STRING:cookies.nba-1.value", "1234") .expectAbsentLong("STRING:cookies.nba-1.expires") .expectAbsentString("STRING:cookies.nba-1.path") .expectAbsentString("STRING:cookies.nba-1.domain") .expect("HTTP.SETCOOKIE:cookies.nba-2", "NBA-2=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT") .expect("STRING:cookies.nba-2.value", "1234") .expect("STRING:cookies.nba-2.expires", "1577836810") .expect("STRING:cookies.nba-2.expires", 1577836810L) .expect("TIME.EPOCH:cookies.nba-2.expires", 1577836810000L) .expectAbsentString("STRING:cookies.nba-2.path") .expectAbsentString("STRING:cookies.nba-2.domain") .expect("HTTP.SETCOOKIE:cookies.nba-3", "NBA-3=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/xx") .expect("STRING:cookies.nba-3.value", "1234") .expect("STRING:cookies.nba-3.expires", "1577836810") .expect("STRING:cookies.nba-3.expires", 1577836810L) .expect("TIME.EPOCH:cookies.nba-3.expires", 1577836810000L) .expect("STRING:cookies.nba-3.path", "/xx") .expectAbsentString("STRING:cookies.nba-3.domain") .expect("HTTP.SETCOOKIE:cookies.nba-4", "NBA-4=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/xx; domain=.basj.es") .expect("STRING:cookies.nba-4.value", "1234") .expect("STRING:cookies.nba-4.expires", "1577836810") .expect("STRING:cookies.nba-4.expires", 1577836810L) .expect("TIME.EPOCH:cookies.nba-4.expires", 1577836810000L) .expect("STRING:cookies.nba-4.path", "/xx") .expect("STRING:cookies.nba-4.domain", ".basj.es") .expect("HTTP.SETCOOKIE:cookies.nba-5", "NBA-5=1234; path=/xx; domain=.basj.es") .expect("STRING:cookies.nba-5.value", "1234") .expectAbsentString("STRING:cookies.nba-5.expires") .expectAbsentLong("STRING:cookies.nba-5.expires") .expectAbsentLong("TIME.EPOCH:cookies.nba-5.expires") .expect("STRING:cookies.nba-5.path", "/xx") .expect("STRING:cookies.nba-5.domain", ".basj.es") .expect("HTTP.SETCOOKIE:cookies.nba-6", "NBA-6=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; domain=.basj.es") .expect("STRING:cookies.nba-6.value", "1234") .expect("STRING:cookies.nba-6.expires", "1577836810") .expect("STRING:cookies.nba-6.expires", 1577836810L) .expect("TIME.EPOCH:cookies.nba-6.expires", 1577836810000L) .expectAbsentString("STRING:cookies.nba-6.path") .expect("STRING:cookies.nba-6.domain", ".basj.es") .expect("HTTP.SETCOOKIE:cookies.nba-7", "NBA-7=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; domain=.basj.es; comment=bla bla bla") .expect("STRING:cookies.nba-7.value", "1234") .expect("STRING:cookies.nba-7.expires", "1577836810") .expect("STRING:cookies.nba-7.expires", 1577836810L) .expect("TIME.EPOCH:cookies.nba-7.expires", 1577836810000L) .expectAbsentString("STRING:cookies.nba-7.path") .expect("STRING:cookies.nba-7.domain", ".basj.es") .expect("STRING:cookies.nba-7.comment", "bla bla bla") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/dissectors/TestGeoIPDissectors.java ================================================ /* * Apache HTTPD logparsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPASNDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCityDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPCountryDissector; import nl.basjes.parse.httpdlog.dissectors.geoip.GeoIPISPDissector; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; class TestGeoIPDissectors { private static final String TEST_MMDB_BASE_DIR = "../../GeoIP2-TestData/test-data/"; private static final String ASN_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoLite2-ASN-Test.mmdb"; private static final String ISP_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoIP2-ISP-Test.mmdb"; private static final String CITY_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoIP2-City-Test.mmdb"; private static final String COUNTRY_TEST_MMDB = TEST_MMDB_BASE_DIR + "GeoIP2-Country-Test.mmdb"; DissectorTester createTester(Dissector dissector) { return DissectorTester.create() .withDissector(dissector) .withPathPrefix(""); } public static class TestGeoIPDissectorsWithPrefix extends TestGeoIPDissectors { // We run the SAME tests again but now wrapped in a parser that does things with a prefix. DissectorTester createTester(Dissector dissector) { return DissectorTester.create() .withParser(new HttpdLoglineParser<>(TestRecord.class, "%h")) .withDissector(dissector) .withPathPrefix("connection.client.host."); } } // ================================================================================================================= // No such file @Test void testBadFileASN() { AssertionError assertionError = assertThrows(AssertionError.class, ()-> createTester(new GeoIPASNDissector("Does not exist")) .withInput("80.100.47.45") .expect("ASN:asn.number", "4444") .checkExpectations()); assertTrue(assertionError.getMessage().contains("Does not exist (No such file or directory)")); } @Test void testBadFileISP() { AssertionError assertionError = assertThrows(AssertionError.class, () -> createTester(new GeoIPISPDissector("Does not exist")) .withInput("80.100.47.45") .expect("ASN:asn.number", "4444") .checkExpectations()); assertTrue(assertionError.getMessage().contains("Does not exist (No such file or directory)")); } @Test void testBadFileCity() { AssertionError assertionError = assertThrows(AssertionError.class, () -> createTester(new GeoIPCityDissector("Does not exist")) .withInput("80.100.47.45") .expect("STRING:continent.name", "Europe") .checkExpectations()); assertTrue(assertionError.getMessage().contains("Does not exist (No such file or directory)")); } @Test void testBadFileCountry() { AssertionError assertionError = assertThrows(AssertionError.class, () -> createTester(new GeoIPCountryDissector("Does not exist")) .withInput("80.100.47.45") .expect("STRING:continent.name", "Europe") .checkExpectations()); assertTrue(assertionError.getMessage().contains("Does not exist (No such file or directory)")); } // ================================================================================================================= // IP not in index @Test void testUnknownIPASN() { createTester(new GeoIPASNDissector(ASN_TEST_MMDB)) .withInput("1.2.3.4") .expectAbsentString("ASN:asn.number") .checkExpectations(); } @Test void testUnknownIPISP() { createTester(new GeoIPISPDissector(ISP_TEST_MMDB)) .withInput("1.2.3.4") .expectAbsentString("ASN:asn.number") .checkExpectations(); } @Test void testUnknownIPCity() { createTester(new GeoIPCityDissector(CITY_TEST_MMDB)) .withInput("1.2.3.4") .expectAbsentString("STRING:continent.name") .checkExpectations(); } @Test void testUnknownIPCountry() { createTester(new GeoIPCountryDissector(COUNTRY_TEST_MMDB)) .withInput("1.2.3.4") .expectAbsentString("STRING:continent.name") .checkExpectations(); } // ================================================================================================================= // Tests with IPv4 @Test void testGeoIPASN() { createTester(new GeoIPASNDissector(ASN_TEST_MMDB)) .withInput("80.100.47.45") .expect("ASN:asn.number", "4444") .expect("ASN:asn.number", 4444L) .expect("STRING:asn.organization", "Basjes Global Network") .checkExpectations(); } @Test void testGeoIPISP() { createTester(new GeoIPISPDissector(ISP_TEST_MMDB)) .withInput("80.100.47.45") .expect("ASN:asn.number", "4444") .expect("ASN:asn.number", 4444L) .expect("STRING:asn.organization", "Basjes Global Network") .expect("STRING:isp.name", "Basjes ISP") .expect("STRING:isp.organization", "Niels Basjes") .checkExpectations(); } @Test void testGeoIPCountry() { createTester(new GeoIPCountryDissector(COUNTRY_TEST_MMDB)) .withInput("80.100.47.45") .expect("STRING:continent.name", "Europe") .expect("STRING:continent.code", "EU") .expect("STRING:country.name", "Netherlands") .expect("STRING:country.iso", "NL") .expect("NUMBER:country.getconfidence", "42") .expect("NUMBER:country.getconfidence", 42L) .expect("BOOLEAN:country.isineuropeanunion", "1") .expect("BOOLEAN:country.isineuropeanunion", 1L) .checkExpectations(); } @Test void testGeoIPCity() { createTester(new GeoIPCityDissector(CITY_TEST_MMDB)) .withInput("80.100.47.45") .expect("STRING:continent.name", "Europe") .expect("STRING:continent.code", "EU") .expect("STRING:country.name", "Netherlands") .expect("STRING:country.iso", "NL") .expect("NUMBER:country.getconfidence", "42") .expect("NUMBER:country.getconfidence", 42L) .expect("BOOLEAN:country.isineuropeanunion", "1") .expect("BOOLEAN:country.isineuropeanunion", 1L) .expect("STRING:subdivision.name", "Noord Holland") .expect("STRING:subdivision.iso", "NH") .expect("STRING:city.name", "Amstelveen") .expect("NUMBER:city.confidence", 1L) .expect("NUMBER:city.geonameid", 1234L) .expect("STRING:postal.code", "1187") .expect("NUMBER:postal.confidence", 2L) .expect("STRING:location.latitude", "52.5") .expect("STRING:location.latitude", 52.5) .expect("STRING:location.longitude", "5.75") .expect("STRING:location.longitude", 5.75) .expect("NUMBER:location.accuracyradius", 4L) .checkExpectations(); } // ================================================================================================================= // Tests with IPv6 @Test void testGeoIPASNIpv6() { createTester(new GeoIPASNDissector(ASN_TEST_MMDB)) .withInput("2001:980:91c0:1:21c:c0ff:fe06:e580") .expect("ASN:asn.number", "6666") .expect("ASN:asn.number", 6666L) .expect("STRING:asn.organization", "Basjes Global Network IPv6") .checkExpectations(); } @Test void testGeoIPISPIpv6() { createTester(new GeoIPISPDissector(ISP_TEST_MMDB)) .withInput("2001:980:91c0:1:21c:c0ff:fe06:e580") .expect("ASN:asn.number", "6666") .expect("ASN:asn.number", 6666L) .expect("STRING:asn.organization", "Basjes Global Network IPv6") .expect("STRING:isp.name", "Basjes ISP IPv6") .expect("STRING:isp.organization", "Niels Basjes IPv6") .checkExpectations(); } @Test void testGeoIPCountryIpv6() { createTester(new GeoIPCountryDissector(COUNTRY_TEST_MMDB)) .withInput("2001:980:91c0:1:21c:c0ff:fe06:e580") .expect("STRING:continent.name", "Europe") .expect("STRING:continent.code", "EU") .expect("STRING:country.name", "Netherlands") .expect("STRING:country.iso", "NL") .expect("NUMBER:country.getconfidence", "42") .expect("NUMBER:country.getconfidence", 42L) .expect("BOOLEAN:country.isineuropeanunion", 1L) .expect("BOOLEAN:country.isineuropeanunion", "1") .checkExpectations(); } @Test void testGeoIPCityIpv6() { createTester(new GeoIPCityDissector(CITY_TEST_MMDB)) .withInput("2001:980:91c0:1:21c:c0ff:fe06:e580") .expect("STRING:continent.name", "Europe") .expect("STRING:continent.code", "EU") .expect("STRING:country.name", "Netherlands") .expect("STRING:country.iso", "NL") .expect("NUMBER:country.getconfidence", "42") .expect("NUMBER:country.getconfidence", 42L) .expect("BOOLEAN:country.isineuropeanunion", "1") .expect("BOOLEAN:country.isineuropeanunion", 1L) .expect("STRING:subdivision.name", "Noord Holland") .expect("STRING:subdivision.iso", "NH") .expect("STRING:city.name", "Amstelveen") .expect("NUMBER:city.confidence", 11L) .expect("NUMBER:city.geonameid", 1234L) .expect("STRING:postal.code", "1187") .expect("NUMBER:postal.confidence", 12L) .expect("STRING:location.latitude", "52.5") .expect("STRING:location.latitude", 52.5) .expect("STRING:location.longitude", "5.75") .expect("STRING:location.longitude", 5.75) .expect("STRING:location.timezone", "Europe/Amsterdam") .expect("NUMBER:location.accuracyradius", 14L) .checkExpectations(); } // ================================================================================================================= // Tests with localhost ... which is NOT in the database @Test void testGeoIPISPLocalhost() { createTester(new GeoIPISPDissector(ISP_TEST_MMDB)) .withInput("127.0.0.1") .expectAbsentString("ASN:asn.number") .expectAbsentLong("ASN:asn.number") .expectAbsentString("STRING:asn.organization") .expectAbsentString("STRING:isp.name") .expectAbsentString("STRING:isp.organization") .checkExpectations(); } @Test void testGeoIPASNLocalhost() { createTester(new GeoIPASNDissector(ASN_TEST_MMDB)) .withInput("127.0.0.1") .expectAbsentString("ASN:asn.number") .expectAbsentLong("ASN:asn.number") .expectAbsentString("STRING:asn.organization") .checkExpectations(); } @Test void testGeoIPCountryLocalhost() { createTester(new GeoIPCountryDissector(COUNTRY_TEST_MMDB)) .withInput("127.0.0.1") .expectAbsentString("STRING:continent.name") .expectAbsentString("STRING:continent.code") .expectAbsentString("STRING:country.name") .expectAbsentString("STRING:country.iso") .expectAbsentString("NUMBER:country.getconfidence") .expectAbsentLong("NUMBER:country.getconfidence") .expectAbsentString("BOOLEAN:country.isineuropeanunion") .expectAbsentLong("BOOLEAN:country.isineuropeanunion") .checkExpectations(); } @Test void testGeoIPCityLocalhost() { createTester(new GeoIPCityDissector(CITY_TEST_MMDB)) .withInput("127.0.0.1") .expectAbsentString("STRING:continent.name") .expectAbsentString("STRING:continent.code") .expectAbsentString("STRING:country.name") .expectAbsentString("STRING:country.iso") .expectAbsentString("NUMBER:country.getconfidence") .expectAbsentLong("NUMBER:country.getconfidence") .expectAbsentString("BOOLEAN:country.isineuropeanunion") .expectAbsentLong("BOOLEAN:country.isineuropeanunion") .expectAbsentString("STRING:city.name") .expectAbsentString("STRING:postal.code") .expectAbsentString("STRING:location.latitude") .expectAbsentDouble("STRING:location.latitude") .expectAbsentString("STRING:location.longitude") .expectAbsentDouble("STRING:location.longitude") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/dissectors/TestHttpFirstLineDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.test.DissectorTester; import org.junit.jupiter.api.Test; class TestHttpFirstLineDissector { @Test void testNormal() { DissectorTester.create() .withDissector(new HttpFirstLineDissector()) .withDissector(new HttpFirstLineProtocolDissector()) .withInput("GET /index.html HTTP/1.1") .expect("HTTP.METHOD:method", "GET") .expect("HTTP.URI:uri", "/index.html") .expect("HTTP.PROTOCOL:protocol", "HTTP") .expect("HTTP.PROTOCOL.VERSION:protocol.version", "1.1") .checkExpectations(); } @Test void testChoppedFirstLine() { DissectorTester.create() .withDissector(new HttpFirstLineDissector()) .withDissector(new HttpFirstLineProtocolDissector()) .withInput("GET /index.html HTT") .expect("HTTP.METHOD:method", "GET") .expect("HTTP.URI:uri", "/index.html HTT") .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.PROTOCOL.VERSION:protocol.version") .checkExpectations(); } @Test void testInvalidFirstLine() { DissectorTester.create() .withDissector(new HttpFirstLineDissector()) .withInput("\\x16\\x03\\x01") .expectAbsentString("HTTP.METHOD:method") .expectAbsentString("HTTP.URI:uri") .checkExpectations(); } @Test void testStrangeCommandVersionControl() { DissectorTester.create() .withDissector(new HttpFirstLineDissector()) .withDissector(new HttpFirstLineProtocolDissector()) .withInput("VERSION-CONTROL /index.html HTTP/1.1") .expect("HTTP.METHOD:method", "VERSION-CONTROL") .expect("HTTP.URI:uri", "/index.html") .expect("HTTP.PROTOCOL:protocol", "HTTP") .expect("HTTP.PROTOCOL.VERSION:protocol.version", "1.1") .checkExpectations(); } @Test void testProtocol() { DissectorTester.create() .withDissector("protocol", new HttpFirstLineProtocolDissector()) .withInput("FOO/1.2") .expect("HTTP.PROTOCOL:protocol", "FOO") .expect("HTTP.PROTOCOL.VERSION:protocol.version", "1.2") .checkExpectations(); } @Test void testChoppedProtocol() { DissectorTester.create() .withDissector("protocol", new HttpFirstLineProtocolDissector()) .withInput("FOO") .expect("HTTP.PROTOCOL:protocol", (String)null) .expect("HTTP.PROTOCOL.VERSION:protocol.version", (String)null) .checkExpectations(); } @Test void testEmptyProtocol1() { DissectorTester.create() .withDissector("protocol", new HttpFirstLineProtocolDissector()) .withInput("") .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.PROTOCOL.VERSION:protocol.version") .checkExpectations(); } @Test void testEmptyProtocol2() { DissectorTester.create() .withDissector("protocol", new HttpFirstLineProtocolDissector()) .withInput("-") .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.PROTOCOL.VERSION:protocol.version") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/dissectors/TestHttpUriDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.test.DissectorTester; import org.junit.jupiter.api.Test; class TestHttpUriDissector { @Test void testFullUrl1() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("http://www.example.com/some/thing/else/index.html?foofoo=bar%20bar") .expect("HTTP.PROTOCOL:protocol", "http") .expectAbsentString("HTTP.USERINFO:userinfo") .expect("HTTP.HOST:host", "www.example.com") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/some/thing/else/index.html") .expect("HTTP.QUERYSTRING:query", "&foofoo=bar%20bar") .expectAbsentString("HTTP.REF:ref") .checkExpectations(); } @Test void testFullUrl2() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("http://www.example.com/some/thing/else/index.html&aap=noot?foofoo=barbar&") .expect("HTTP.PROTOCOL:protocol", "http") .expectAbsentString("HTTP.USERINFO:userinfo") .expect("HTTP.HOST:host", "www.example.com") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/some/thing/else/index.html") .expect("HTTP.QUERYSTRING:query", "&aap=noot&foofoo=barbar&") .expectAbsentString("HTTP.REF:ref") .checkExpectations(); } @Test void testFullUrl3() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("http://www.example.com:8080/some/thing/else/index.html&aap=noot?foofoo=barbar&#blabla") .expect("HTTP.PROTOCOL:protocol", "http") .expectAbsentString("HTTP.USERINFO:userinfo") .expect("HTTP.HOST:host", "www.example.com") .expect("HTTP.PORT:port", "8080") .expect("HTTP.PATH:path", "/some/thing/else/index.html") .expect("HTTP.QUERYSTRING:query", "&aap=noot&foofoo=barbar&") .expect("HTTP.REF:ref", "blabla") .checkExpectations(); } @Test void testFullUrl4() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("/some/thing/else/index.html?foofoo=barbar#blabla") .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.USERINFO:userinfo") .expectAbsentString("HTTP.HOST:host") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/some/thing/else/index.html") .expect("HTTP.QUERYSTRING:query", "&foofoo=barbar") .expect("HTTP.REF:ref", "blabla") .checkExpectations(); } @Test void testFullUrl5() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("/some/thing/else/index.html&aap=noot?foofoo=bar%20bar&#bla%20bla") .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.USERINFO:userinfo") .expectAbsentString("HTTP.HOST:host") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/some/thing/else/index.html") .expect("HTTP.QUERYSTRING:query", "&aap=noot&foofoo=bar%20bar&") .expect("HTTP.REF:ref", "bla bla") .checkExpectations(); } @Test void testAndroidApp1() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("android-app://com.google.android.googlequicksearchbox") .expect("HTTP.PROTOCOL:protocol", "android-app") .expectAbsentString("HTTP.USERINFO:userinfo") .expect("HTTP.HOST:host", "com.google.android.googlequicksearchbox") .expectAbsentString("HTTP.PORT:port") .expectAbsentString("HTTP.PATH:path") .expectAbsentString("HTTP.QUERYSTRING:query") .expectAbsentString("HTTP.REF:ref") .checkExpectations(); } @Test void testAndroidApp2() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("android-app://com.google.android.googlequicksearchbox/https/www.google.com") .expect("HTTP.PROTOCOL:protocol", "android-app") .expectAbsentString("HTTP.USERINFO:userinfo") .expect("HTTP.HOST:host", "com.google.android.googlequicksearchbox") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/https/www.google.com") .expectAbsentString("HTTP.QUERYSTRING:query") .expectAbsentString("HTTP.REF:ref") .checkExpectations(); } @Test void testBadURI() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("/some/thing/else/[index.html&aap=noot?foofoo=bar%20bar #bla%20bla ") // Java URI parser fails on '[' here. .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.USERINFO:userinfo") .expectAbsentString("HTTP.HOST:host") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/some/thing/else/[index.html") .expect("HTTP.QUERYSTRING:query", "&aap=noot&foofoo=bar%20bar%20") .expect("HTTP.REF:ref", "bla bla ") .checkExpectations(); } @Test void testBadURIEncoding() { DissectorTester.create() .withDissector(new HttpUriDissector()) // Java URI parser fails on 'Malformed escape pair' .withInput("/index.html&promo=Give-50%-discount&promo=And-do-%Another-Wrong&last=also bad %#bla%20bla ") // here ^ and here ^ and here ^ .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.USERINFO:userinfo") .expectAbsentString("HTTP.HOST:host") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/index.html") .expect("HTTP.QUERYSTRING:query", "&promo=Give-50%25-discount&promo=And-do-%25Another-Wrong&last=also%20bad%20%25") .expect("HTTP.REF:ref", "bla bla ") .checkExpectations(); } @Test void testBadURIMultiPercentEncoding() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withDissector(new QueryStringFieldDissector()) .withInput("/index.html?Linkid=%%%3dv(%40Foo)%3d%%%&emcid=B%ar") .expectAbsentString("HTTP.PROTOCOL:protocol") .expectAbsentString("HTTP.USERINFO:userinfo") .expectAbsentString("HTTP.HOST:host") .expectAbsentString("HTTP.PORT:port") .expect("HTTP.PATH:path", "/index.html") .expect("HTTP.QUERYSTRING:query", "&Linkid=%25%25%3dv(%40Foo)%3d%25%25%25&emcid=B%25ar") .expect("STRING:query.linkid", "%%=v(@Foo)=%%%") .expectAbsentString("HTTP.REF:ref") .checkExpectations(); } @Test void testDoubleHashes() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withInput("https://www.basjes.nl/#foo#bar#bazz#bla#bla#") .withInput("https://www.basjes.nl/path/?s2a=&Referrer=ADV1234#product_title&f=API&subid=?s2a=#product_title&name=12341234") .withInput("https://www.basjes.nl/path/?Referrer=ADV1234#&f=API&subid=#&name=12341234") .withInput("https://www.basjes.nl/path?sort=price&filter=new&sortOrder=asc") .withInput("https://www.basjes.nl/login.html?redirectUrl=https%3A%2F%2Fwww.basjes.nl%2Faccount%2Findex.html" + "&_requestid=1234#x3D;12341234&Referrer=ENTblablabla") .expect("HTTP.HOST:host", "www.basjes.nl") .checkExpectations(); } @Test void testHTMLEntities() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withDissector(new QueryStringFieldDissector()) .withInput("https://www.basjes.nl/?utm_campaign=aaaa&utm_source=bbbb&utm_medium=email&utm_content=>€&foo;%2010x%20foo%20bar") .expect("HTTP.HOST:host", "www.basjes.nl") // Note that the bad HTML entities have been converted into something "less bad" .expect("HTTP.QUERYSTRING:query", "&utm_campaign=aaaa&utm_source=bbbb&utm_medium=email&utm_content=%3E%E2%82%AC*foo;%2010x%20foo%20bar") .expect("STRING:query.utm_campaign", "aaaa") .expect("STRING:query.utm_source", "bbbb") .expect("STRING:query.utm_medium", "email") .expect("STRING:query.utm_content", ">€*foo; 10x foo bar") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/dissectors/TestModUniqueIdDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.test.DissectorTester; import org.junit.jupiter.api.Test; class TestModUniqueIdDissector { @Test void testUniqueId1() { // This test case was verified using https://github.com/web-online/mod-unique-id-decode //$ ./mod_unique_id_uudecoder -i VaGTKApid0AAALpaNo0AAAAC //unique_id.stamp = Sun Jul 12 00:05:28 2015 //unique_id.in_addr = 10.98.119.64 //unique_id.pid = 47706 //unique_id.counter = 13965 //unique_id.threadIndex = 2 DissectorTester.create() .withDissector(new ModUniqueIdDissector()) .withInput("VaGTKApid0AAALpaNo0AAAAC") .expect("TIME.EPOCH:epoch", "1436652328000") .expect("IP:ip", "10.98.119.64") .expect("PROCESSID:processid", "47706") .expect("COUNTER:counter", "13965") .expect("THREAD_INDEX:threadindex", "2") .checkExpectations(); } @Test void testUniqueId2() { // This test case was verified using https://github.com/web-online/mod-unique-id-decode //$ ./mod_unique_id_uudecoder -i Ucdv38CoEJwAAEusp6EAAADz //unique_id.stamp = Sun Jun 23 23:59:59 2013 //unique_id.in_addr = 192.168.16.156 //unique_id.pid = 19372 //unique_id.counter = 42913 //unique_id.threadIndex = 243 DissectorTester.create() .withDissector(new ModUniqueIdDissector()) .withInput("Ucdv38CoEJwAAEusp6EAAADz") .expect("TIME.EPOCH:epoch", "1372024799000") .expect("IP:ip", "192.168.16.156") .expect("PROCESSID:processid", "19372") .expect("COUNTER:counter", "42913") .expect("THREAD_INDEX:threadindex", "243") .checkExpectations(); } @Test void testBadUniqueIdTooShort() { DissectorTester.create() .withDissector(new ModUniqueIdDissector()) .withInput("Ucdv38CoEJwAAEusp6EAAAD") // BAD: 1 letter too short .expectAbsentString("TIME.EPOCH:epoch") .expectAbsentString("IP:ip") .expectAbsentString("PROCESSID:processid") .expectAbsentString("COUNTER:counter") .expectAbsentString("THREAD_INDEX:threadindex") .checkExpectations(); } @Test void testBadUniqueIdNotBase64() { DissectorTester.create() .withDissector(new ModUniqueIdDissector()) .withInput("Ucdv38CoEJwAAEusp6EAAAD!") // BAD: 1 letter wrong .expectAbsentString("TIME.EPOCH:epoch") .expectAbsentString("IP:ip") .expectAbsentString("PROCESSID:processid") .expectAbsentString("COUNTER:counter") .expectAbsentString("THREAD_INDEX:threadindex") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/dissectors/TestQueryStringDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.test.DissectorTester; import org.junit.jupiter.api.Test; class TestQueryStringDissector { @Test void testQueryString() { DissectorTester.create() .withDissector(new HttpUriDissector()) .withDissector(new QueryStringFieldDissector()) .withInput("/some/thing/else/index.html&aap=1&noot=&mies&") .expect("HTTP.PATH:path", "/some/thing/else/index.html") .expect("HTTP.QUERYSTRING:query", "&aap=1&noot=&mies&") .expect("STRING:query.aap", "1") // Present with value .expect("STRING:query.noot", "") // Present without value .expect("STRING:query.mies", "") // Present without value .expectAbsentString("STRING:query.wim") // NOT Present .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/dissectors/TestTimeStampDissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.dissectors; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.httpdlog.HttpdLogFormatDissector; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import java.time.DateTimeException; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.WeekFields; import java.util.Locale; import java.util.stream.Stream; import static java.util.Locale.ENGLISH; import static java.util.Locale.ROOT; import static java.util.Locale.UK; import static java.util.Locale.US; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; // CHECKSTYLE.OFF: LineLength class TestTimeStampDissector { @Test void ensureDefaultLocaleFollowsISOWeekFields() { WeekFields localeWeekFields = WeekFields.of(new TimeStampDissector().getLocale()); WeekFields isoWeekFields = WeekFields.ISO; assertEquals(localeWeekFields.getFirstDayOfWeek(), isoWeekFields.getFirstDayOfWeek()); assertEquals(localeWeekFields.getMinimalDaysInFirstWeek(), isoWeekFields.getMinimalDaysInFirstWeek()); } @Test void testTimeStampDissector() { DissectorTester.create() .withDissector(new TimeStampDissector()) .withInput("31/Dec/2012:23:00:44 -0700") .expect("TIME.EPOCH:epoch", "1357020044000") .expect("TIME.EPOCH:epoch", 1357020044000L) .expect("TIME.YEAR:year", "2012") .expect("TIME.YEAR:year", 2012L) .expect("TIME.MONTH:month", "12") .expect("TIME.MONTH:month", 12L) .expect("TIME.MONTHNAME:monthname", "December") .expect("TIME.DAY:day", "31") .expect("TIME.DAY:day", 31L) .expect("TIME.HOUR:hour", "23") .expect("TIME.HOUR:hour", 23L) .expect("TIME.MINUTE:minute", "0") .expect("TIME.MINUTE:minute", 0L) .expect("TIME.SECOND:second", "44") .expect("TIME.SECOND:second", 44L) .expect("TIME.DATE:date", "2012-12-31") .expect("TIME.TIME:time", "23:00:44") .expect("TIME.ZONE:timezone", "-07:00") .expect("TIME.YEAR:year_utc", "2013") .expect("TIME.YEAR:year_utc", 2013L) .expect("TIME.MONTH:month_utc", "1") .expect("TIME.MONTH:month_utc", 1L) .expect("TIME.MONTHNAME:monthname_utc", "January") .expect("TIME.DAY:day_utc", "1") .expect("TIME.DAY:day_utc", 1L) .expect("TIME.HOUR:hour_utc", "6") .expect("TIME.HOUR:hour_utc", 6L) .expect("TIME.MINUTE:minute_utc", "0") .expect("TIME.MINUTE:minute_utc", 0L) .expect("TIME.SECOND:second_utc", "44") .expect("TIME.SECOND:second_utc", 44L) .expect("TIME.DATE:date_utc", "2013-01-01") .expect("TIME.TIME:time_utc", "06:00:44") .checkExpectations(); } @Test void testTimeStampDissectorPossibles() { DissectorTester.create() .withDissector(new TimeStampDissector()) .expectPossible("TIME.EPOCH:epoch") .expectPossible("TIME.YEAR:year") .expectPossible("TIME.MONTH:month") .expectPossible("TIME.MONTHNAME:monthname") .expectPossible("TIME.DAY:day") .expectPossible("TIME.HOUR:hour") .expectPossible("TIME.MINUTE:minute") .expectPossible("TIME.SECOND:second") .expectPossible("TIME.DATE:date") .expectPossible("TIME.TIME:time") .expectPossible("TIME.ZONE:timezone") .expectPossible("TIME.YEAR:year_utc") .expectPossible("TIME.MONTH:month_utc") .expectPossible("TIME.MONTHNAME:monthname_utc") .expectPossible("TIME.DAY:day_utc") .expectPossible("TIME.HOUR:hour_utc") .expectPossible("TIME.MINUTE:minute_utc") .expectPossible("TIME.SECOND:second_utc") .expectPossible("TIME.DATE:date_utc") .expectPossible("TIME.TIME:time_utc") .checkExpectations(); } @Test void testStrftimeStampDissectorPossibles() { DissectorTester.create() .withDissector(new HttpdLogFormatDissector("%{%Y-%m-%dT%H:%M:%S%z}t")) .withInput("2012-12-31T23:00:44-0700") .expect("TIME.EPOCH:request.receive.time.epoch", "1357020044000") .expectPossible("TIME.LOCALIZEDSTRING:request.receive.time") .expectPossible("TIME.EPOCH:request.receive.time.epoch") .expectPossible("TIME.YEAR:request.receive.time.year") .expectPossible("TIME.MONTH:request.receive.time.month") .expectPossible("TIME.MONTHNAME:request.receive.time.monthname") .expectPossible("TIME.DAY:request.receive.time.day") .expectPossible("TIME.HOUR:request.receive.time.hour") .expectPossible("TIME.MINUTE:request.receive.time.minute") .expectPossible("TIME.SECOND:request.receive.time.second") .expectPossible("TIME.DATE:request.receive.time.date") .expectPossible("TIME.TIME:request.receive.time.time") .expectPossible("TIME.ZONE:request.receive.time.timezone") .expectPossible("TIME.YEAR:request.receive.time.year_utc") .expectPossible("TIME.MONTH:request.receive.time.month_utc") .expectPossible("TIME.MONTHNAME:request.receive.time.monthname_utc") .expectPossible("TIME.DAY:request.receive.time.day_utc") .expectPossible("TIME.HOUR:request.receive.time.hour_utc") .expectPossible("TIME.MINUTE:request.receive.time.minute_utc") .expectPossible("TIME.SECOND:request.receive.time.second_utc") .expectPossible("TIME.DATE:request.receive.time.date_utc") .expectPossible("TIME.TIME:request.receive.time.time_utc") .checkExpectations(); } @Test void testTimeStamUpperLowerCaseVariations() { DissectorTester.create() .withDissector(new TimeStampDissector()) .withInput("30/sep/2016:00:00:06 +0000") .withInput("30/Sep/2016:00:00:06 +0000") .withInput("30/sEp/2016:00:00:06 +0000") .withInput("30/SEp/2016:00:00:06 +0000") .withInput("30/seP/2016:00:00:06 +0000") .withInput("30/SeP/2016:00:00:06 +0000") .withInput("30/sEP/2016:00:00:06 +0000") .withInput("30/SEP/2016:00:00:06 +0000") .expect("TIME.YEAR:year_utc", "2016") .expect("TIME.MONTH:month_utc", "9") .expect("TIME.DAY:day_utc", "30") .checkExpectations(); } private static Stream locales() { return Stream.of( Arguments.of("Root", ROOT), Arguments.of("English", ENGLISH), Arguments.of("US", US), Arguments.of("UK", UK), Arguments.of("AU", new Locale("en", "AU")), Arguments.of("NL", new Locale("nl", "NL")) ); } @ParameterizedTest(name = "Test {index}: {0} ({1})") @MethodSource("locales") void testTimeStampMonthNameVariations(String name, Locale locale) { DissectorTester.create() .withDissector(new TimeStampDissector().setLocale(locale)) .withInput("30/jun/2016:00:00:06 +0000") .withInput("30/June/2016:00:00:06 +0000") .expect("TIME.YEAR:year_utc", "2016") .expect("TIME.MONTH:month_utc", "6") .expect("TIME.DAY:day_utc", "30") .checkExpectations(); DissectorTester.create() .withDissector(new TimeStampDissector().setLocale(locale)) .withInput("30/jul/2016:00:00:06 +0000") .withInput("30/July/2016:00:00:06 +0000") .expect("TIME.YEAR:year_utc", "2016") .expect("TIME.MONTH:month_utc", "7") .expect("TIME.DAY:day_utc", "30") .checkExpectations(); DissectorTester.create() .withDissector(new TimeStampDissector().setLocale(locale)) .withInput("30/sep/2016:00:00:06 +0000") .withInput("30/Sept/2016:00:00:06 +0000") .expect("TIME.YEAR:year_utc", "2016") .expect("TIME.MONTH:month_utc", "9") .expect("TIME.DAY:day_utc", "30") .checkExpectations(); AssertionError dissectionFailure; dissectionFailure = assertThrows(AssertionError.class, () -> { DissectorTester.create() .withDissector(new TimeStampDissector().setLocale(locale)) .withInput("30/xyz/2016:00:00:06 +0000") // Intentionally bad : xyz .expect("TIME.YEAR:year_utc", "2016") .expect("TIME.MONTH:month_utc", "9") .expect("TIME.DAY:day_utc", "30") .checkExpectations(); }); assertTrue(dissectionFailure.getMessage().contains("could not be parsed at index")); dissectionFailure = assertThrows(AssertionError.class, () -> { DissectorTester.create() .withDissector(new TimeStampDissector().setLocale(locale)) .withInput("30/sepr/2016:00:00:06 +0000") // Intentionally bad: sepr .expect("TIME.YEAR:year_utc", "2016") .expect("TIME.MONTH:month_utc", "9") .expect("TIME.DAY:day_utc", "30") .checkExpectations(); }); assertTrue(dissectionFailure.getMessage().contains("could not be parsed at index")); } @Test void testHandlingOfNotYetImplementedSpecialTimeFormat() { // Test both the original form and the documented workaround. String logformat = "%{%Y-%m-%dT%H:%M:%S%z}t | %{timestamp}i"; String input = "2012-12-31T23:00:44 -0700 | 2012-12-31T23:00:44 -0700"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(input) .expect("TIME.LOCALIZEDSTRING:request.receive.time", "2012-12-31T23:00:44 -0700") .expect("HTTP.HEADER:request.header.timestamp", "2012-12-31T23:00:44 -0700") .checkExpectations(); } @Test void testSpecialTimeFormat() { DissectorTester.create() .withDissector(new HttpdLogFormatDissector("%{%Y-%m-%dT%H:%M:%S%z}t")) .withInput("2012-12-31T23:00:44-0700") .expect("TIME.EPOCH:request.receive.time.epoch", "1357020044000") .expect("TIME.EPOCH:request.receive.time.epoch", 1357020044000L) .expect("TIME.YEAR:request.receive.time.year", "2012") .expect("TIME.YEAR:request.receive.time.year", 2012L) .expect("TIME.MONTH:request.receive.time.month", "12") .expect("TIME.MONTH:request.receive.time.month", 12L) .expect("TIME.MONTHNAME:request.receive.time.monthname", "December") .expect("TIME.DAY:request.receive.time.day", "31") .expect("TIME.DAY:request.receive.time.day", 31L) .expect("TIME.HOUR:request.receive.time.hour", "23") .expect("TIME.HOUR:request.receive.time.hour", 23L) .expect("TIME.MINUTE:request.receive.time.minute", "0") .expect("TIME.MINUTE:request.receive.time.minute", 0L) .expect("TIME.SECOND:request.receive.time.second", "44") .expect("TIME.SECOND:request.receive.time.second", 44L) .expect("TIME.DATE:request.receive.time.date", "2012-12-31") .expect("TIME.TIME:request.receive.time.time", "23:00:44") .expect("TIME.ZONE:request.receive.time.timezone", "-07:00") .expect("TIME.YEAR:request.receive.time.year_utc", "2013") .expect("TIME.YEAR:request.receive.time.year_utc", 2013L) .expect("TIME.MONTH:request.receive.time.month_utc", "1") .expect("TIME.MONTH:request.receive.time.month_utc", 1L) .expect("TIME.MONTHNAME:request.receive.time.monthname_utc", "January") .expect("TIME.DAY:request.receive.time.day_utc", "1") .expect("TIME.DAY:request.receive.time.day_utc", 1L) .expect("TIME.HOUR:request.receive.time.hour_utc", "6") .expect("TIME.HOUR:request.receive.time.hour_utc", 6L) .expect("TIME.MINUTE:request.receive.time.minute_utc", "0") .expect("TIME.MINUTE:request.receive.time.minute_utc", 0L) .expect("TIME.SECOND:request.receive.time.second_utc", "44") .expect("TIME.SECOND:request.receive.time.second_utc", 44L) .expect("TIME.DATE:request.receive.time.date_utc", "2013-01-01") .expect("TIME.TIME:request.receive.time.time_utc", "06:00:44") .checkExpectations(); } @Test void testSpecialTimeFormatBegin() { DissectorTester.create() .withDissector(new HttpdLogFormatDissector("%{begin:%Y-%m-%dT%H:%M:%S%z}t")) .withInput("2012-12-31T23:00:44-0700") .expect("TIME.EPOCH:request.receive.time.begin.epoch", "1357020044000") .checkExpectations(); } @Test void testSpecialTimeFormatEnd() { DissectorTester.create() .withDissector(new HttpdLogFormatDissector("%{end:%Y-%m-%dT%H:%M:%S%z}t")) .withInput("2012-12-31T23:00:44-0700") .expect("TIME.EPOCH:request.receive.time.end.epoch", "1357020044000") .checkExpectations(); } @Test void testSpecialTimeFormatMultiFields1() { String logline = "12/21/16 2016-12-21 20:50 20:50:25 08:50:25 PM Wed Wednesday Dec December 21 2016 Dec 20 08 356 20 8 12 50 PM 1482349825 25 3 2016 +0100"; String logformat = "%{%D %F %R %T %r %a %A %b %B %d %G %h %H %I %j %k %l %m %M %p %s %S %u %Y %z}t"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", "1482349825000") .expect("TIME.DATE:request.receive.time.date", "2016-12-21") .expect("TIME.TIME:request.receive.time.time", "20:50:25") .expect("TIME.YEAR:request.receive.time.year", "2016") .expect("TIME.MONTH:request.receive.time.month", "12") .expect("TIME.MONTHNAME:request.receive.time.monthname", "December") .expect("TIME.YEAR:request.receive.time.weekyear", "2016") .expect("TIME.WEEK:request.receive.time.weekofweekyear", "51") .expect("TIME.DAY:request.receive.time.day", "21") .expect("TIME.HOUR:request.receive.time.hour", "20") .expect("TIME.MINUTE:request.receive.time.minute", "50") .expect("TIME.SECOND:request.receive.time.second", "25") .expect("TIME.MILLISECOND:request.receive.time.millisecond", "0") .expect("TIME.ZONE:request.receive.time.timezone", "+01:00") .expect("TIME.DATE:request.receive.time.date_utc", "2016-12-21") .expect("TIME.TIME:request.receive.time.time_utc", "19:50:25") .expect("TIME.YEAR:request.receive.time.year_utc", "2016") .expect("TIME.MONTH:request.receive.time.month_utc", "12") .expect("TIME.MONTHNAME:request.receive.time.monthname_utc", "December") .expect("TIME.YEAR:request.receive.time.weekyear_utc", "2016") .expect("TIME.WEEK:request.receive.time.weekofweekyear_utc", "51") .expect("TIME.DAY:request.receive.time.day_utc", "21") .expect("TIME.HOUR:request.receive.time.hour_utc", "19") .expect("TIME.MINUTE:request.receive.time.minute_utc", "50") .expect("TIME.SECOND:request.receive.time.second_utc", "25") .expect("TIME.MILLISECOND:request.receive.time.millisecond_utc", "0") .checkExpectations(); } @Test void testSpecialTimeFormatMultiFields2() { String logline = "127.0.0.1 - - [22/Dec/2016:00:09:54 +0100] \"GET / HTTP/1.1\" 200 3525 \"12/22/16 2016-12-22 00:09 00:09:54 12:09:54 AM Thu Thursday Dec December 22 2016 Dec 00 12 357 0 12 12 09 AM 1482361794 54 4 2016 +0100\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36\""; String logformat = "%h %l %u %t \"%r\" %>s %O \"%{%D %F %R %T %r %a %A %b %B %d %G %h %H %I %j %k %l %m %M %p %s %S %u %Y %z}t\" \"%{User-Agent}i\""; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", "1482361794000") .expect("TIME.DATE:request.receive.time.date", "2016-12-22") .expect("TIME.TIME:request.receive.time.time", "00:09:54") .expect("TIME.YEAR:request.receive.time.year", "2016") .expect("TIME.MONTH:request.receive.time.month", "12") .expect("TIME.MONTHNAME:request.receive.time.monthname", "December") .expect("TIME.YEAR:request.receive.time.weekyear", "2016") .expect("TIME.WEEK:request.receive.time.weekofweekyear", "51") .expect("TIME.DAY:request.receive.time.day", "22") .expect("TIME.HOUR:request.receive.time.hour", "0") .expect("TIME.MINUTE:request.receive.time.minute", "9") .expect("TIME.SECOND:request.receive.time.second", "54") .expect("TIME.MILLISECOND:request.receive.time.millisecond", "0") .expect("TIME.ZONE:request.receive.time.timezone", "+01:00") .expect("TIME.DATE:request.receive.time.date_utc", "2016-12-21") .expect("TIME.TIME:request.receive.time.time_utc", "23:09:54") .expect("TIME.YEAR:request.receive.time.year_utc", "2016") .expect("TIME.MONTH:request.receive.time.month_utc", "12") .expect("TIME.MONTHNAME:request.receive.time.monthname_utc", "December") .expect("TIME.YEAR:request.receive.time.weekyear_utc", "2016") .expect("TIME.WEEK:request.receive.time.weekofweekyear_utc", "51") .expect("TIME.DAY:request.receive.time.day_utc", "21") .expect("TIME.HOUR:request.receive.time.hour_utc", "23") .expect("TIME.MINUTE:request.receive.time.minute_utc", "9") .expect("TIME.SECOND:request.receive.time.second_utc", "54") .expect("TIME.MILLISECOND:request.receive.time.millisecond_utc", "0") .checkExpectations(); } @Test void testSpecialTimeLeadingSpaces1() { String logline = "12/21/16 2016-12-21 20:50 20:50:25 08:50:25 PM Wed Wednesday Dec December 21 2016 Dec 20 08 356 20 8 12 50 PM 1482349825 25 3 2016 +0100"; String logformat = "%{%D %F %R %T %r %a %A %b %B %d %G %h %H %I %j %k %l %m %M %p %s %S %u %Y %z}t"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", "1482349825000") .checkExpectations(); } @Test void testSpecialTimeLeadingSpaces2a() { String logline = "127.0.0.1 - - [01/Jan/2017:13:01:21 +0100] \"GET / HTTP/1.1\" 200 3525 \"01/01/17 2017-01-01 13:01 13:01:21 01:01:21 PM Sun Sunday Jan January 01 2017 Jan 13 01 001 13 1 01 01 PM 21 7 2017 +0100\" \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36\""; String logformat = "%h %l %u %t \"%r\" %>s %O \"%{%D %F %R %T %r %a %A %b %B %d %G %h %H %I %j %k %l %m %M %p %S %u %Y %z}t\" \"%{User-Agent}i\""; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", "1483272081000") .checkExpectations(); } @Test void testMultipleSpecialTime() { // As described here: http://httpd.apache.org/docs/current/mod/mod_log_config.html#examples // You can use the %{format}t directive multiple times to build up a time format using the extended format tokens like msec_frac: // Timestamp including milliseconds // "%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t" String logline = "01/Jan/2017 21:52:58.483 +0100"; // The original logformat // String logformat = "%{%d/%b/%Y %T}t.%{msec_frac}t %{%z}t"; // The transformation // logformat = logformat.replaceAll("\\}t([^%{]+)%\\{","$1"); // The reformatted result. String logformat = "%{%d/%b/%Y %T.msec_frac %z}t"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", "1483303978483") .checkExpectations(); } @Test void testReportedSpecialTime() { String logline = "28/feb/2017:03:39:40 +0800"; String logformat = "%{%d/%b/%Y:%H:%M:%S %z}t"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", "1488224380000") .checkExpectations(); } @Test void testAllStrfFieldsLowValues() { ZonedDateTime dateTime = ZonedDateTime.of(LocalDateTime.of(2001, 1, 2, 3, 4, 5, 678901234), ZoneId.of("CET")); checkStrfField(dateTime, "%a", "Tue"); // The abbreviated name of the day of the week according to the current locale. checkStrfField(dateTime, "%A", "Tuesday"); // The full name of the day of the week according to the current locale. checkStrfField(dateTime, "%b", "Jan"); // The abbreviated month name according to the current locale. checkStrfField(dateTime, "%h", "Jan"); // Equivalent to %b. checkStrfField(dateTime, "%B", "January"); // The full month name according to the current locale.; checkStrfField(dateTime, "%d", "02"); // The day of the month as a decimal number (range 01 to 31). checkStrfField(dateTime, "%D", "01/02/01"); // Equivalent to %m/%d/%y. (Yecch—for Americans only) checkStrfField(dateTime, "%e", " 2"); // Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. checkStrfField(dateTime, "%F", "2001-01-02"); // Equivalent to %Y-%m-%d (the ISO 8601 date format). checkStrfField(dateTime, "%G", "2001"); // The ISO 8601 week-based year (see NOTES) with century as a decimal number. checkStrfField(dateTime, "%g", "01"); // Like %G, but without century, that is, with a 2-digit year (00–99). checkStrfField(dateTime, "%H", "03"); // The hour as a decimal number using a 24-hour clock (range 00 to 23). checkStrfField(dateTime, "%I", "03"); // The hour as a decimal number using a 12-hour clock (range 01 to 12). checkStrfField(dateTime, "%j", "002"); // The day of the year as a decimal number (range 001 to 366). checkStrfField(dateTime, "%k", " 3"); // The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H) checkStrfField(dateTime, "%l", " 3"); // The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. (See also %I) checkStrfField(dateTime, "%m", "01"); // The month as a decimal number (range 01 to 12). checkStrfField(dateTime, "%M", "04"); // The minute as a decimal number (range 00 to 59). checkStrfField(dateTime, "%p", "AM"); // Either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale. Noon is treated as "PM" and midnight as "AM". checkStrfField(dateTime, "%P", "am"); // Like %p but in lowercase: "am" or "pm" or a corresponding string for the current locale. checkStrfField(dateTime, "%r", "03:04:05 AM"); // The time in a.m. or p.m. notation. In the POSIX locale this is equivalent to %I:%M:%S %p. checkStrfField(dateTime, "%R", "03:04"); // The time in 24-hour notation (%H:%M). For a version including the seconds, see %T below. checkStrfField(dateTime, "%s", "978401045"); // The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). checkStrfField(dateTime, "%S", "05"); // The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds) checkStrfField(dateTime, "%T", "03:04:05"); // The time in 24-hour notation (%H:%M:%S). checkStrfField(dateTime, "%u", "2"); // The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. checkStrfField(dateTime, "%V", "1"); // The ISO 8601 week number (see NOTES) of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the new year. See also %U and %W. checkStrfField(dateTime, "%W", "01"); // The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01. checkStrfField(dateTime, "%y", "01"); // The year as a decimal number without a century (range 00 to 99). checkStrfField(dateTime, "%Y", "2001"); // The year as a decimal number including the century. checkStrfField(dateTime, "%z", "+0100"); // The +hhmm or -hhmm numeric timezone. checkStrfField(dateTime, "%Z", "CET"); // The timezone name or abbreviation. checkStrfField(dateTime, "msec_frac", "678"); // Apache HTTPD specific: milliseconds fraction checkStrfField(dateTime, "usec_frac", "678901"); // Apache HTTPD specific: microseconds fraction checkStrfField(dateTime, "%F %T.msec_frac %z", "2001-01-02 03:04:05.678 +0100"); checkStrfField(dateTime, "%F %T.usec_frac %z", "2001-01-02 03:04:05.678901 +0100"); // With extra '%' checkStrfField(dateTime, "%msec_frac", "678"); // Apache HTTPD specific: milliseconds fraction checkStrfField(dateTime, "%usec_frac", "678901"); // Apache HTTPD specific: microseconds fraction checkStrfField(dateTime, "%F %T.msec_frac %z", "2001-01-02 03:04:05.678 +0100"); checkStrfField(dateTime, "%F %T.usec_frac %z", "2001-01-02 03:04:05.678901 +0100"); } @Test void testAllStrfFieldsHighValues() { ZonedDateTime dateTime = ZonedDateTime.of(LocalDateTime.of(2017, 11, 12, 23, 14, 15, 678901234), ZoneId.of("CET")); checkStrfField(dateTime, "%a", "Sun"); // The abbreviated name of the day of the week according to the current locale. checkStrfField(dateTime, "%A", "Sunday"); // The full name of the day of the week according to the current locale. checkStrfField(dateTime, "%b", "Nov"); // The abbreviated month name according to the current locale. checkStrfField(dateTime, "%h", "Nov"); // Equivalent to %b. checkStrfField(dateTime, "%B", "November"); // The full month name according to the current locale.; checkStrfField(dateTime, "%d", "12"); // The day of the month as a decimal number (range 01 to 31). checkStrfField(dateTime, "%D", "11/12/17"); // Equivalent to %m/%d/%y. (Yecch—for Americans only) checkStrfField(dateTime, "%e", "12"); // Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. checkStrfField(dateTime, "%F", "2017-11-12"); // Equivalent to %Y-%m-%d (the ISO 8601 date format). checkStrfField(dateTime, "%G", "2017"); // The ISO 8601 week-based year (see NOTES) with century as a decimal number. The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %Y, except that if the ISO week number belongs to the previous or next year, that year is used instead. checkStrfField(dateTime, "%g", "17"); // Like %G, but without century, that is, with a 2-digit year (00–99). checkStrfField(dateTime, "%H", "23"); // The hour as a decimal number using a 24-hour clock (range 00 to 23). checkStrfField(dateTime, "%I", "11"); // The hour as a decimal number using a 12-hour clock (range 01 to 12). checkStrfField(dateTime, "%j", "316"); // The day of the year as a decimal number (range 001 to 366). checkStrfField(dateTime, "%k", "23"); // The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H) checkStrfField(dateTime, "%l", "11"); // The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. (See also %I) checkStrfField(dateTime, "%m", "11"); // The month as a decimal number (range 01 to 12). checkStrfField(dateTime, "%M", "14"); // The minute as a decimal number (range 00 to 59). checkStrfField(dateTime, "%p", "PM"); // Either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale. Noon is treated as "PM" and midnight as "AM". checkStrfField(dateTime, "%P", "pm"); // Like %p but in lowercase: "am" or "pm" or a corresponding string for the current locale. checkStrfField(dateTime, "%r", "11:14:15 PM"); // The time in a.m. or p.m. notation. In the POSIX locale this is equivalent to %I:%M:%S %p. checkStrfField(dateTime, "%R", "23:14"); // The time in 24-hour notation (%H:%M). For a version including the seconds, see %T below. checkStrfField(dateTime, "%s", "1510524855"); // The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). checkStrfField(dateTime, "%S", "15"); // The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds) checkStrfField(dateTime, "%T", "23:14:15"); // The time in 24-hour notation (%H:%M:%S). checkStrfField(dateTime, "%u", "7"); // The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. checkStrfField(dateTime, "%V", "45"); // The ISO 8601 week number (see NOTES) of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the new year. See also %U and %W. checkStrfField(dateTime, "%W", "45"); // The week number of the current year as a decimal number, range 00 to 53, starting with the first Monday as the first day of week 01. checkStrfField(dateTime, "%y", "17"); // The year as a decimal number without a century (range 00 to 99). checkStrfField(dateTime, "%Y", "2017"); // The year as a decimal number including the century. checkStrfField(dateTime, "%z", "+0100"); // The +hhmm or -hhmm numeric timezone. checkStrfField(dateTime, "%Z", "CET"); // The timezone name or abbreviation. checkStrfField(dateTime, "msec_frac", "678"); // Apache HTTPD specific: milliseconds fraction checkStrfField(dateTime, "usec_frac", "678901"); // Apache HTTPD specific: microseconds fraction checkStrfField(dateTime, "%F %T.msec_frac %z", "2017-11-12 23:14:15.678 +0100"); checkStrfField(dateTime, "%F %T.usec_frac %z", "2017-11-12 23:14:15.678901 +0100"); // With extra '%' checkStrfField(dateTime, "%msec_frac", "678"); // Apache HTTPD specific: milliseconds fraction checkStrfField(dateTime, "%usec_frac", "678901"); // Apache HTTPD specific: microseconds fraction checkStrfField(dateTime, "%F %T.%msec_frac %z", "2017-11-12 23:14:15.678 +0100"); checkStrfField(dateTime, "%F %T.%usec_frac %z", "2017-11-12 23:14:15.678901 +0100"); } private void checkStrfField(ZonedDateTime dateTime, String strffield, String expected) { try { DateTimeFormatter dateTimeFormatter = StrfTimeToDateTimeFormatter.convert(strffield, ZoneId.of("CET")); assertNotNull(dateTimeFormatter); String result = dateTime.format(dateTimeFormatter); assertEquals(expected, result, "Incorrect field " + strffield); } catch (DateTimeException dte) { fail("DateTimeException for field " + strffield + " "+ dte.getMessage()); } } @Test void ensureUnsupportedFields() { checkUnsupported("%c"); // The preferred date and time representation for the current locale. checkUnsupported("%C"); // The century number (year/100) as a 2-digit integer. checkUnsupported("%U"); // The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01. See also %V and %W. checkUnsupported("%w"); // The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u. checkUnsupported("%x"); // The preferred date representation for the current locale without the time. checkUnsupported("%X"); // The preferred time representation for the current locale without the date. checkUnsupported("%+"); // The date and time in date(1) format. } private void checkUnsupported(String strffield) { try { StrfTimeToDateTimeFormatter.convert(strffield); } catch (StrfTimeToDateTimeFormatter.UnsupportedStrfField e) { return; // This is actually good } catch (Exception e) { fail("Unexpected exception:" + e.getMessage()); } fail("DateTimeException for field " + strffield + " should be unsupported"); } @Test void strfTimeWithMissingTimeZone() { DissectorTester.create() .withDissector(new HttpdLogFormatDissector("%{%F %H:%M:%S}t")) .withInput("2017-12-25 00:00:00") .expect("TIME.EPOCH:request.receive.time.epoch", 1514160000000L) .checkExpectations(); String logformat = "%a %l %u %{%F %H:%M:%S}t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" t=%D"; String logline = "192.168.85.3 - - 2017-12-25 00:00:00 \"GET /up.html HTTP/1.0\" 203 8 \"-\" \"HTTP-Monitor/1.1\" \"-\" t=4920"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", 1514160000000L) .checkExpectations(); } @Test void testStrfTimeMsecfrac() { String logformat = "%a %l %u %{%F %H:%M:%S.msec_frac}t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" t=%D"; String logline = "192.168.85.3 - - 2017-12-25 00:00:42.123 \"GET /up.html HTTP/1.0\" 203 8 \"-\" \"HTTP-Monitor/1.1\" \"-\" t=4920"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", 1514160042123L) .expect("TIME.SECOND:request.receive.time.second", 42L) .expect("TIME.MILLISECOND:request.receive.time.millisecond", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond", 123000L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond", 123000000L) .expect("TIME.MILLISECOND:request.receive.time.millisecond_utc", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond_utc", 123000L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond_utc", 123000000L) .checkExpectations(); } @Test void testStrfTimeMsecfracP() { String logformat = "%a %l %u %{%F %H:%M:%S.%msec_frac}t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" t=%D"; String logline = "192.168.85.3 - - 2017-12-25 00:00:42.123 \"GET /up.html HTTP/1.0\" 203 8 \"-\" \"HTTP-Monitor/1.1\" \"-\" t=4920"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", 1514160042123L) .expect("TIME.SECOND:request.receive.time.second", 42L) .expect("TIME.MILLISECOND:request.receive.time.millisecond", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond", 123000L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond", 123000000L) .expect("TIME.MILLISECOND:request.receive.time.millisecond_utc", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond_utc", 123000L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond_utc", 123000000L) .checkExpectations(); } @Test void testStrfTimeUsecfrac() { String logformat = "%a %l %u %{%F %H:%M:%S.usec_frac}t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" t=%D"; String logline = "192.168.85.3 - - 2017-12-25 00:00:42.123456 \"GET /up.html HTTP/1.0\" 203 8 \"-\" \"HTTP-Monitor/1.1\" \"-\" t=4920"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", 1514160042123L) .expect("TIME.SECOND:request.receive.time.second", 42L) .expect("TIME.MILLISECOND:request.receive.time.millisecond", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond", 123456L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond", 123456000L) .expect("TIME.MILLISECOND:request.receive.time.millisecond_utc", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond_utc", 123456L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond_utc", 123456000L) .checkExpectations(); } @Test void testStrfTimeUsecfracP() { String logformat = "%a %l %u %{%F %H:%M:%S.%usec_frac}t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" t=%D"; String logline = "192.168.85.3 - - 2017-12-25 00:00:42.123456 \"GET /up.html HTTP/1.0\" 203 8 \"-\" \"HTTP-Monitor/1.1\" \"-\" t=4920"; DissectorTester.create() .withDissector(new HttpdLogFormatDissector(logformat)) .withInput(logline) .expect("TIME.EPOCH:request.receive.time.epoch", 1514160042123L) .expect("TIME.SECOND:request.receive.time.second", 42L) .expect("TIME.MILLISECOND:request.receive.time.millisecond", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond", 123456L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond", 123456000L) .expect("TIME.MILLISECOND:request.receive.time.millisecond_utc", 123L) .expect("TIME.MICROSECOND:request.receive.time.microsecond_utc", 123456L) .expect("TIME.NANOSECOND:request.receive.time.nanosecond_utc", 123456000L) .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/nginxmodules/NginxAllFieldsTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.nginxmodules; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import org.junit.jupiter.api.Test; import java.util.List; import static org.junit.jupiter.api.Assertions.assertFalse; // This test simply checks which of the fields known in the Nginx documentation have been implemented. class NginxAllFieldsTest { // All variables mentioned on https://nginx.org/en/docs/varindex.html @Test void ensureAllFieldsAreHandled() { checkVariable("$arg_"); // ngx_http_core_module checkVariable("$args"); // ngx_http_core_module checkVariable("$binary_remote_addr"); // ngx_http_core_module checkVariable("$binary_remote_addr"); // ngx_stream_core_module checkVariable("$body_bytes_sent"); // ngx_http_core_module checkVariable("$bytes_received"); // ngx_stream_core_module checkVariable("$bytes_sent"); // ngx_http_core_module checkVariable("$bytes_sent"); // ngx_http_log_module checkVariable("$bytes_sent"); // ngx_stream_core_module checkVariable("$connection"); // ngx_http_core_module checkVariable("$connection"); // ngx_http_log_module checkVariable("$connection"); // ngx_stream_core_module checkVariable("$connection_requests"); // ngx_http_core_module checkVariable("$connection_requests"); // ngx_http_log_module checkVariable("$content_length"); // ngx_http_core_module checkVariable("$content_type"); // ngx_http_core_module checkVariable("$cookie_"); // ngx_http_core_module checkVariable("$document_root"); // ngx_http_core_module checkVariable("$document_uri"); // ngx_http_core_module checkVariable("$host"); // ngx_http_core_module checkVariable("$hostname"); // ngx_http_core_module checkVariable("$hostname"); // ngx_stream_core_module checkVariable("$http_"); // ngx_http_core_module checkVariable("$https"); // ngx_http_core_module checkVariable("$is_args"); // ngx_http_core_module checkVariable("$limit_rate"); // ngx_http_core_module checkVariable("$msec"); // ngx_http_core_module checkVariable("$msec"); // ngx_http_log_module checkVariable("$msec"); // ngx_stream_core_module checkVariable("$nginx_version"); // ngx_http_core_module checkVariable("$nginx_version"); // ngx_stream_core_module checkVariable("$pid"); // ngx_http_core_module checkVariable("$pid"); // ngx_stream_core_module checkVariable("$pipe"); // ngx_http_core_module checkVariable("$pipe"); // ngx_http_log_module checkVariable("$protocol"); // ngx_stream_core_module checkVariable("$proxy_protocol_addr"); // ngx_http_core_module checkVariable("$proxy_protocol_addr"); // ngx_stream_core_module checkVariable("$proxy_protocol_port"); // ngx_http_core_module checkVariable("$proxy_protocol_port"); // ngx_stream_core_module checkVariable("$query_string"); // ngx_http_core_module checkVariable("$realpath_root"); // ngx_http_core_module checkVariable("$remote_addr"); // ngx_http_core_module checkVariable("$remote_addr"); // ngx_stream_core_module checkVariable("$remote_port"); // ngx_http_core_module checkVariable("$remote_port"); // ngx_stream_core_module checkVariable("$remote_user"); // ngx_http_core_module checkVariable("$request"); // ngx_http_core_module checkVariable("$request_body"); // ngx_http_core_module checkVariable("$request_body_file"); // ngx_http_core_module checkVariable("$request_completion"); // ngx_http_core_module checkVariable("$request_filename"); // ngx_http_core_module checkVariable("$request_id"); // ngx_http_core_module checkVariable("$request_length"); // ngx_http_core_module checkVariable("$request_length"); // ngx_http_log_module checkVariable("$request_method"); // ngx_http_core_module checkVariable("$request_time"); // ngx_http_core_module checkVariable("$request_time"); // ngx_http_log_module checkVariable("$request_uri"); // ngx_http_core_module checkVariable("$scheme"); // ngx_http_core_module checkVariable("$sent_http_somename"); // ngx_http_core_module checkVariable("$sent_trailer_somename"); // ngx_http_core_module checkVariable("$server_addr"); // ngx_http_core_module checkVariable("$server_addr"); // ngx_stream_core_module checkVariable("$server_name"); // ngx_http_core_module checkVariable("$server_port"); // ngx_http_core_module checkVariable("$server_port"); // ngx_stream_core_module checkVariable("$server_protocol"); // ngx_http_core_module checkVariable("$session_time"); // ngx_stream_core_module checkVariable("$status"); // ngx_http_core_module checkVariable("$status"); // ngx_http_log_module checkVariable("$status"); // ngx_stream_core_module checkVariable("$tcpinfo_rtt"); // ngx_http_core_module checkVariable("$tcpinfo_rttvar"); // ngx_http_core_module checkVariable("$tcpinfo_snd_cwnd"); // ngx_http_core_module checkVariable("$tcpinfo_rcv_space"); // ngx_http_core_module checkVariable("$time_iso8601"); // ngx_http_core_module checkVariable("$time_iso8601"); // ngx_http_log_module checkVariable("$time_iso8601"); // ngx_stream_core_module checkVariable("$time_local"); // ngx_http_core_module checkVariable("$time_local"); // ngx_http_log_module checkVariable("$time_local"); // ngx_stream_core_module checkVariable("$secure_link"); // ngx_http_secure_link_module // NOT FOR LOGGING: checkVariable("$secure_link_expires"); // ngx_http_secure_link_module // NOT FOR LOGGING: checkVariable("$session_log_binary_id"); // ngx_http_session_log_module checkVariable("$session_log_id"); // ngx_http_session_log_module checkVariable("$slice_range"); // ngx_http_slice_module checkVariable("$proxy_add_x_forwarded_for"); // ngx_http_proxy_module checkVariable("$proxy_host"); // ngx_http_proxy_module checkVariable("$proxy_port"); // ngx_http_proxy_module checkVariable("$ssl_cipher"); // ngx_http_ssl_module checkVariable("$ssl_cipher"); // ngx_stream_ssl_module checkVariable("$ssl_ciphers"); // ngx_http_ssl_module checkVariable("$ssl_ciphers"); // ngx_stream_ssl_module checkVariable("$ssl_client_cert"); // ngx_http_ssl_module checkVariable("$ssl_client_cert"); // ngx_stream_ssl_module checkVariable("$ssl_client_escaped_cert"); // ngx_http_ssl_module checkVariable("$ssl_client_fingerprint"); // ngx_http_ssl_module checkVariable("$ssl_client_fingerprint"); // ngx_stream_ssl_module checkVariable("$ssl_client_i_dn"); // ngx_http_ssl_module checkVariable("$ssl_client_i_dn"); // ngx_stream_ssl_module checkVariable("$ssl_client_i_dn_legacy"); // ngx_http_ssl_module checkVariable("$ssl_client_raw_cert"); // ngx_http_ssl_module checkVariable("$ssl_client_raw_cert"); // ngx_stream_ssl_module checkVariable("$ssl_client_s_dn"); // ngx_http_ssl_module checkVariable("$ssl_client_s_dn"); // ngx_stream_ssl_module checkVariable("$ssl_client_s_dn_legacy"); // ngx_http_ssl_module checkVariable("$ssl_client_serial"); // ngx_http_ssl_module checkVariable("$ssl_client_serial"); // ngx_stream_ssl_module checkVariable("$ssl_client_v_end"); // ngx_http_ssl_module checkVariable("$ssl_client_v_end"); // ngx_stream_ssl_module checkVariable("$ssl_client_v_remain"); // ngx_http_ssl_module checkVariable("$ssl_client_v_remain"); // ngx_stream_ssl_module checkVariable("$ssl_client_v_start"); // ngx_http_ssl_module checkVariable("$ssl_client_v_start"); // ngx_stream_ssl_module checkVariable("$ssl_client_verify"); // ngx_http_ssl_module checkVariable("$ssl_client_verify"); // ngx_stream_ssl_module checkVariable("$ssl_curves"); // ngx_http_ssl_module checkVariable("$ssl_curves"); // ngx_stream_ssl_module checkVariable("$ssl_early_data"); // ngx_http_ssl_module checkVariable("$ssl_preread_alpn_protocols"); // ngx_stream_ssl_preread_module checkVariable("$ssl_preread_protocol"); // ngx_stream_ssl_preread_module checkVariable("$ssl_preread_server_name"); // ngx_stream_ssl_preread_module checkVariable("$ssl_protocol"); // ngx_http_ssl_module checkVariable("$ssl_protocol"); // ngx_stream_ssl_module checkVariable("$ssl_server_name"); // ngx_http_ssl_module checkVariable("$ssl_server_name"); // ngx_stream_ssl_module checkVariable("$ssl_session_id"); // ngx_http_ssl_module checkVariable("$ssl_session_id"); // ngx_stream_ssl_module checkVariable("$ssl_session_reused"); // ngx_http_ssl_module checkVariable("$ssl_session_reused"); // ngx_stream_ssl_module checkVariable("$upstream_addr"); // ngx_http_upstream_module checkVariable("$upstream_addr"); // ngx_stream_upstream_module checkVariable("$upstream_bytes_received"); // ngx_http_upstream_module checkVariable("$upstream_bytes_received"); // ngx_stream_upstream_module checkVariable("$upstream_bytes_sent"); // ngx_http_upstream_module checkVariable("$upstream_bytes_sent"); // ngx_stream_upstream_module checkVariable("$upstream_cache_status"); // ngx_http_upstream_module checkVariable("$upstream_connect_time"); // ngx_http_upstream_module checkVariable("$upstream_connect_time"); // ngx_stream_upstream_module checkVariable("$upstream_cookie_"); // ngx_http_upstream_module checkVariable("$upstream_first_byte_time"); // ngx_stream_upstream_module checkVariable("$upstream_header_time"); // ngx_http_upstream_module checkVariable("$upstream_http_"); // ngx_http_upstream_module checkVariable("$upstream_queue_time"); // ngx_http_upstream_module checkVariable("$upstream_response_length"); // ngx_http_upstream_module checkVariable("$upstream_response_time"); // ngx_http_upstream_module checkVariable("$upstream_session_time"); // ngx_stream_upstream_module checkVariable("$upstream_status"); // ngx_http_upstream_module checkVariable("$upstream_trailer_"); // ngx_http_upstream_module checkVariable("$uri"); // ngx_http_core_module checkVariable("$uid_got"); // ngx_http_userid_module checkVariable("$uid_reset"); // ngx_http_userid_module checkVariable("$uid_set"); // ngx_http_userid_module checkVariable("$ancient_browser"); // ngx_http_browser_module checkVariable("$modern_browser"); // ngx_http_browser_module checkVariable("$msie"); // ngx_http_browser_module checkVariable("$connections_active"); // ngx_http_stub_status_module checkVariable("$connections_reading"); // ngx_http_stub_status_module checkVariable("$connections_waiting"); // ngx_http_stub_status_module checkVariable("$connections_writing"); // ngx_http_stub_status_module checkVariable("$date_gmt"); // ngx_http_ssi_module checkVariable("$date_local"); // ngx_http_ssi_module checkVariable("$fastcgi_path_info"); // ngx_http_fastcgi_module checkVariable("$fastcgi_script_name"); // ngx_http_fastcgi_module checkVariable("$geoip_area_code"); // ngx_http_geoip_module checkVariable("$geoip_area_code"); // ngx_stream_geoip_module checkVariable("$geoip_city"); // ngx_http_geoip_module checkVariable("$geoip_city"); // ngx_stream_geoip_module checkVariable("$geoip_city_continent_code"); // ngx_http_geoip_module checkVariable("$geoip_city_continent_code"); // ngx_stream_geoip_module checkVariable("$geoip_city_country_code"); // ngx_http_geoip_module checkVariable("$geoip_city_country_code"); // ngx_stream_geoip_module checkVariable("$geoip_city_country_code3"); // ngx_http_geoip_module checkVariable("$geoip_city_country_code3"); // ngx_stream_geoip_module checkVariable("$geoip_city_country_name"); // ngx_http_geoip_module checkVariable("$geoip_city_country_name"); // ngx_stream_geoip_module checkVariable("$geoip_country_code"); // ngx_http_geoip_module checkVariable("$geoip_country_code"); // ngx_stream_geoip_module checkVariable("$geoip_country_code3"); // ngx_http_geoip_module checkVariable("$geoip_country_code3"); // ngx_stream_geoip_module checkVariable("$geoip_country_name"); // ngx_http_geoip_module checkVariable("$geoip_country_name"); // ngx_stream_geoip_module checkVariable("$geoip_dma_code"); // ngx_http_geoip_module checkVariable("$geoip_dma_code"); // ngx_stream_geoip_module checkVariable("$geoip_latitude"); // ngx_http_geoip_module checkVariable("$geoip_latitude"); // ngx_stream_geoip_module checkVariable("$geoip_longitude"); // ngx_http_geoip_module checkVariable("$geoip_longitude"); // ngx_stream_geoip_module checkVariable("$geoip_org"); // ngx_http_geoip_module checkVariable("$geoip_org"); // ngx_stream_geoip_module checkVariable("$geoip_postal_code"); // ngx_http_geoip_module checkVariable("$geoip_postal_code"); // ngx_stream_geoip_module checkVariable("$geoip_region"); // ngx_http_geoip_module checkVariable("$geoip_region"); // ngx_stream_geoip_module checkVariable("$geoip_region_name"); // ngx_http_geoip_module checkVariable("$geoip_region_name"); // ngx_stream_geoip_module checkVariable("$gzip_ratio"); // ngx_http_gzip_module checkVariable("$spdy"); // ngx_http_spdy_module checkVariable("$spdy_request_priority"); // ngx_http_spdy_module checkVariable("$http2"); // ngx_http_v2_module checkVariable("$invalid_referer"); // ngx_http_referer_module checkVariable("$jwt_claim_foobar"); // ngx_http_auth_jwt_module checkVariable("$jwt_header_foobar"); // ngx_http_auth_jwt_module checkVariable("$memcached_key"); // ngx_http_memcached_module checkVariable("$realip_remote_addr"); // ngx_http_realip_module checkVariable("$realip_remote_addr"); // ngx_stream_realip_module checkVariable("$realip_remote_port"); // ngx_http_realip_module checkVariable("$realip_remote_port"); // ngx_stream_realip_module // Everything that is mentioned on // https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/log-format/ checkVariable("$proxy_protocol_addr"); // remote address if proxy protocol is enabled checkVariable("$remote_addr"); // remote address if proxy protocol is disabled (default) checkVariable("$the_real_ip"); // the source IP address of the client checkVariable("$remote_user"); // user name supplied with the Basic authentication checkVariable("$time_local"); // local time in the Common Log Format checkVariable("$request"); // full original request line checkVariable("$status"); // response status checkVariable("$body_bytes_sent"); // number of bytes sent to a client, not counting the response header checkVariable("$http_referer"); // value of the Referer header checkVariable("$http_user_agent"); // value of User-Agent header checkVariable("$request_length"); // request length (including request line, header, and request body) checkVariable("$request_time"); // time elapsed since the first bytes were read from the client checkVariable("$proxy_upstream_name"); // name of the upstream. The format is upstream--- checkVariable("$upstream_addr"); // the IP address and port (or the path to the domain socket) of the upstream server. checkVariable("$upstream_response_length"); // the length of the response obtained from the upstream server checkVariable("$upstream_response_time"); // time spent on receiving the response from the upstream server checkVariable("$upstream_status"); // status code of the response obtained from the upstream server checkVariable("$req_id"); // the randomly generated ID of the request // Additionals checkVariable("$namespace"); // namespace of the ingress checkVariable("$ingress_name"); // name of the ingress checkVariable("$service_name"); // name of the service checkVariable("$service_port"); // port of the service } public void checkVariable(String variableName) { List allPossible = DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, "# " + variableName + " #")) .getPossible(); allPossible.forEach(p -> assertFalse(p.startsWith("UNKNOWN_NGINX_VARIABLE"), p)); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/nginxmodules/NginxUpstreamTest.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.nginxmodules; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.core.test.TestRecord; import nl.basjes.parse.httpdlog.HttpdLoglineParser; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; // CHECKSTYLE.OFF: LineLength class NginxUpstreamTest { private static final Logger LOG = LoggerFactory.getLogger(NginxUpstreamTest.class); private static class SingleFieldTestcase { final String logformat; final String logline; final String fieldName; final String expectedValue; SingleFieldTestcase(String logformat, String logline, String fieldName, String expectedValue) { this.logformat = logformat; this.logline = logline; this.fieldName = fieldName; this.expectedValue = expectedValue; } } @Test void testBasicLogFormat() { // From: http://articles.slicehost.com/2010/8/27/customizing-nginx-web-logs String logFormat = "\"$upstream_addr\" \"$upstream_bytes_received\""; String logLine = "\"192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80\" \"1, 2, 3 : 4, 5\""; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .expect("UPSTREAM_ADDR_LIST:nginxmodule.upstream.addr", "192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.0.value", "192.168.1.1:80") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.0.redirected", "192.168.1.1:80") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.1.value", "192.168.1.2:80") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.1.redirected", "192.168.1.2:80") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.2.value", "unix:/tmp/sock") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.2.redirected", "192.168.10.1:80") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.3.value", "192.168.10.2:80") .expect("UPSTREAM_ADDR:nginxmodule.upstream.addr.3.redirected", "192.168.10.2:80") .expectAbsentString("UPSTREAM_ADDR:nginxmodule.upstream.addr.4.value") .expectAbsentString("UPSTREAM_ADDR:nginxmodule.upstream.addr.4.redirected") .expect("UPSTREAM_BYTES_LIST:nginxmodule.upstream.bytes.received", "1, 2, 3 : 4, 5") .expect("BYTES:nginxmodule.upstream.bytes.received.0.value", "1") .expect("BYTES:nginxmodule.upstream.bytes.received.0.redirected", "1") .expect("BYTES:nginxmodule.upstream.bytes.received.1.value", "2") .expect("BYTES:nginxmodule.upstream.bytes.received.1.redirected", "2") .expect("BYTES:nginxmodule.upstream.bytes.received.2.value", "3") .expect("BYTES:nginxmodule.upstream.bytes.received.2.redirected", "4") .expect("BYTES:nginxmodule.upstream.bytes.received.3.value", "5") .expect("BYTES:nginxmodule.upstream.bytes.received.3.redirected", "5") .expectAbsentString("BYTES:nginxmodule.upstream.bytes.received.4.value") .expectAbsentString("BYTES:nginxmodule.upstream.bytes.received.4.redirected") .checkExpectations() .printPossible() .printAllPossibleValues(); } @Test void testFullLine() { String logFormat = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\" \"$http_x_forwarded_for\" $request_time $upstream_response_time $pipe"; String logLine = "10.77.150.123 - - [15/Dec/2018:19:27:57 -0500] \"GET /25.chunk.js HTTP/1.1\" 200 84210 \"https://api.demo.com/\" \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36\" \"-\" 0.002 0.002 ."; DissectorTester.create() .verbose() .withParser(new HttpdLoglineParser<>(TestRecord.class, logFormat)) .withInput(logLine) .expect("SECOND_MILLIS:nginxmodule.upstream.response.time.0.value", "0.002") .expect("SECOND_MILLIS:nginxmodule.upstream.response.time.0.redirected", "0.002") .expect("MICROSECONDS:nginxmodule.upstream.response.time.0.value", "2000") .expect("MICROSECONDS:nginxmodule.upstream.response.time.0.redirected", "2000") .checkExpectations() // .printPossible(); .printAllPossibleValues(); } @Test void validateAllFields() { List fieldsTests = new ArrayList<>(); String addrList = "192.168.1.1:80, 192.168.1.2:80, unix:/tmp/sock : 192.168.10.1:80, 192.168.10.2:80"; final String numList = "1, 2, 3 : 4, 5"; final String timeList = "1.001, 2.002, 3.003 : 4.004, 5.005"; final String statusList = "111, 222, 333 : 444, 555"; fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.0.value", "192.168.1.1:80")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.0.redirected", "192.168.1.1:80")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.1.value", "192.168.1.2:80")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.1.redirected", "192.168.1.2:80")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.2.value", "unix:/tmp/sock")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.2.redirected", "192.168.10.1:80")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.3.value", "192.168.10.2:80")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.3.redirected", "192.168.10.2:80")); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_addr", addrList, "UPSTREAM_ADDR:nginxmodule.upstream.addr.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.0.value", "1")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.0.redirected", "1")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.1.value", "2")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.1.redirected", "2")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.2.value", "3")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.2.redirected", "4")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.3.value", "5")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.3.redirected", "5")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_received", numList, "BYTES:nginxmodule.upstream.bytes.received.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.0.value", "1")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.0.redirected", "1")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.1.value", "2")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.1.redirected", "2")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.2.value", "3")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.2.redirected", "4")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.3.value", "5")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.3.redirected", "5")); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_bytes_sent", numList, "BYTES:nginxmodule.upstream.bytes.sent.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_cache_status", "STALE", "UPSTREAM_CACHE_STATUS:nginxmodule.upstream.cache.status", "STALE")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.0.value", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.0.redirected", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.1.value", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.1.redirected", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.2.value", "3.003")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.2.redirected", "4.004")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.3.value", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.3.redirected", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_connect_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.connect.time.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_cookie_mycookie", "MyValue", "HTTP.COOKIE:nginxmodule.upstream.response.cookies.mycookie", "MyValue")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.0.value", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.0.redirected", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.1.value", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.1.redirected", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.2.value", "3.003")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.2.redirected", "4.004")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.3.value", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.3.redirected", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_header_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.header.time.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_http_myheader", "MyValue", "HTTP.HEADER:nginxmodule.upstream.header.myheader", "MyValue")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.0.value", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.0.redirected", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.1.value", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.1.redirected", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.2.value", "3.003")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.2.redirected", "4.004")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.3.value", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.3.redirected", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_queue_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.queue.time.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.0.value", "1")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.0.redirected", "1")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.1.value", "2")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.1.redirected", "2")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.2.value", "3")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.2.redirected", "4")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.3.value", "5")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.3.redirected", "5")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_response_length", numList, "BYTES:nginxmodule.upstream.response.length.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.0.value", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.0.redirected", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.1.value", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.1.redirected", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.2.value", "3.003")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.2.redirected", "4.004")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.3.value", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.3.redirected", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_response_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.response.time.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.0.value", "111")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.0.redirected", "111")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.1.value", "222")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.1.redirected", "222")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.2.value", "333")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.2.redirected", "444")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.3.value", "555")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.3.redirected", "555")); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_status", statusList, "UPSTREAM_STATUS:nginxmodule.upstream.status.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_trailer_mytrailer", "MyValue", "HTTP.TRAILER:nginxmodule.upstream.trailer.mytrailer", "MyValue")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.0.value", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.0.redirected", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.1.value", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.1.redirected", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.2.value", "3.003")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.2.redirected", "4.004")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.3.value", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.3.redirected", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_first_byte_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.first_byte.time.4.redirected", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.0.value", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.0.redirected", "1.001")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.1.value", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.1.redirected", "2.002")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.2.value", "3.003")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.2.redirected", "4.004")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.3.value", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.3.redirected", "5.005")); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.4.value", null)); fieldsTests.add(new SingleFieldTestcase("$upstream_session_time", timeList, "SECOND_MILLIS:nginxmodule.upstream.session.time.4.redirected", null)); for (SingleFieldTestcase testCase: fieldsTests) { DissectorTester tester = DissectorTester.create() .printSeparator() .withParser(new HttpdLoglineParser<>(TestRecord.class, testCase.logformat)) .withInput(testCase.logline); if (testCase.expectedValue == null) { tester.expectAbsentString(testCase.fieldName); } else { tester.expect(testCase.fieldName, testCase.expectedValue); } tester .checkExpectations(); } } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/java/nl/basjes/parse/httpdlog/translate/TestTranslators.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog.translate; import nl.basjes.parse.core.test.DissectorTester; import nl.basjes.parse.httpdlog.dissectors.translate.ConvertCLFIntoNumber; import nl.basjes.parse.httpdlog.dissectors.translate.ConvertNumberIntoCLF; import org.junit.jupiter.api.Test; class TestTranslators { @Test void testCLFToNumberMin() { DissectorTester.create() .withDissector("root", new ConvertCLFIntoNumber("IN", "OUT")) .withInput(null) // A '-' in the input file goes into the dissector as a null value .expect("OUT:root", 0L) .checkExpectations(); } @Test void testCLFToNumber0() { DissectorTester.create() .withDissector("root", new ConvertCLFIntoNumber("IN", "OUT")) .withInput("0") .expect("OUT:root", 0L) .checkExpectations(); } @Test void testCLFToNumber1() { DissectorTester.create() .withDissector("root", new ConvertCLFIntoNumber("IN", "OUT")) .withInput("1") .expect("OUT:root", 1L) .checkExpectations(); } @Test void testNumberToCLF0() { DissectorTester.create() .withDissector("root", new ConvertNumberIntoCLF("IN", "OUT")) .withInput("0") .expect("OUT:root", 0L) .expect("OUT:root", "0") .checkExpectations(); } @Test void testNumberToCLF1() { DissectorTester.create() .withDissector("root", new ConvertNumberIntoCLF("IN", "OUT")) .withInput("1") .expect("OUT:root", 1L) .expect("OUT:root", "1") .checkExpectations(); } } ================================================ FILE: httpdlog/httpdlog-parser/src/test/resources/log4j.properties ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Root logger option log4j.rootLogger=INFO, stdout #, file log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.threshold=INFO log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n ## file appender #log4j.appender.file=org.apache.log4j.RollingFileAppender #log4j.appender.file.File=target/debug.log #log4j.appender.file.threshold=DEBUG #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n #log4j.appender.file.Append=false ================================================ FILE: httpdlog/httpdlog-serde/pom.xml ================================================ 4.0.0 httpdlog nl.basjes.parse.httpdlog 6.0.1-SNAPSHOT httpdlog-serde Parser - Apache HTTPD - HCatalog SerDe none 21 21 org.apache.hadoop hadoop-client ${hadoop.version} provided slf4j-reload4j org.slf4j org.apache.hive hive-serde ${hive.version} provided log4j-slf4j-impl org.apache.logging.log4j org.pentaho pentaho-aggdesigner-algorithm org.apache.hive hive-exec ${hive.version} provided log4j-slf4j-impl org.apache.logging.log4j log4j log4j log4j-1.2-api org.apache.logging.log4j org.pentaho pentaho-aggdesigner-algorithm org.apache.hive hive-common ${hive.version} provided log4j-slf4j-impl org.apache.logging.log4j log4j-1.2-api org.apache.logging.log4j org.pentaho pentaho-aggdesigner-algorithm ${project.groupId} httpdlog-inputformat ${project.version} nl.basjes.parse parser-core ${project.version} tests test org.apache.maven.plugins maven-toolchains-plugin 3.2.0 select-jdk-toolchain [21,22) org.apache.maven.plugins maven-surefire-plugin --add-opens=java.base/java.net=ALL-UNNAMED org.apache.maven.plugins maven-assembly-plugin make-super-jar package single src/main/assembly/udf.xml true / org.jacoco jacoco-maven-plugin ================================================ FILE: httpdlog/httpdlog-serde/src/main/assembly/udf.xml ================================================ udf jar false false true runtime ${project.build.outputDirectory} ${file.separator} ================================================ FILE: httpdlog/httpdlog-serde/src/main/java/nl/basjes/parse/httpdlog/ApacheHttpdlogDeserializer.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import nl.basjes.hadoop.input.ParsedRecord; import nl.basjes.parse.core.Casts; import nl.basjes.parse.core.Dissector; import nl.basjes.parse.core.Parser; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.serde.serdeConstants; import org.apache.hadoop.hive.serde2.AbstractSerDe; import org.apache.hadoop.hive.serde2.SerDeException; import org.apache.hadoop.hive.serde2.SerDeStats; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory; import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils; import org.apache.hadoop.io.Text; import org.apache.hadoop.io.Writable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import static nl.basjes.parse.core.Casts.DOUBLE; import static nl.basjes.parse.core.Casts.LONG; import static nl.basjes.parse.core.Casts.STRING; import static org.apache.hadoop.hive.serde.serdeConstants.BIGINT_TYPE_NAME; import static org.apache.hadoop.hive.serde.serdeConstants.DOUBLE_TYPE_NAME; import static org.apache.hadoop.hive.serde.serdeConstants.STRING_TYPE_NAME; /** * Hive SerDe for accessing Apache Access log files. * An example DDL statement * would be: *
 *
 * ADD JAR target/httpdlog-serde-1.7-SNAPSHOT-job.jar;
 * CREATE EXTERNAL TABLE nbasjes.clicks (
 *       ip           STRING
 *      ,timestamp    BIGINT
 *      ,useragent    STRING
 *      ,referrer     STRING
 *      ,bui          STRING
 *      ,screenHeight BIGINT
 *      ,screenWidth  BIGINT
 *      )
 * ROW FORMAT SERDE 'nl.basjes.parse.apachehttpdlog.ApacheHttpdlogDeserializer'
 * WITH SERDEPROPERTIES (
 *       "logformat"       = "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{Cookie}i\" %T %V"
 *      ,"map:request.firstline.uri.query.g" = "HTTP.URI"
 *      ,"map:request.firstline.uri.query.r" = "HTTP.URI"
 *
 *      ,"field:timestamp" = "TIME.EPOCH:request.receive.time.epoch"
 *      ,"field:ip"        = "IP:connection.client.host"
 *      ,"field:useragent" = "HTTP.USERAGENT:request.user-agent"
 *
 *      ,"field:referrer"  = "STRING:request.firstline.uri.query.g.query.referrer"
 *      ,"field:bui"       = "HTTP.COOKIE:request.cookies.bui"
 *
 *      ,"load:nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector" = "x"
 *      ,"map:request.firstline.uri.query.s" = "SCREENRESOLUTION"
 *      ,"field:screenHeight" = "SCREENHEIGHT:request.firstline.uri.query.s.height"
 *      ,"field:screenWidth"  = "SCREENWIDTH:request.firstline.uri.query.s.width"
 *      )
 * STORED AS TEXTFILE
 * LOCATION "/user/nbasjes/clicks";
 * 
*/ //@SerDeSpec(schemaProps = { // serdeConstants.LIST_COLUMNS, serdeConstants.LIST_COLUMN_TYPES, // RegexSerDe.INPUT_REGEX, RegexSerDe.OUTPUT_FORMAT_STRING, // RegexSerDe.INPUT_REGEX_CASE_SENSITIVE //}) public class ApacheHttpdlogDeserializer extends AbstractSerDe { private static final Logger LOG = LoggerFactory.getLogger(ApacheHttpdlogDeserializer.class); private static final String FIELD = "field:"; private static final String MAP_FIELD = "map:"; private static final int MAP_FIELD_LENGTH = MAP_FIELD.length(); private static final String LOAD_DISSECTOR = "load:"; private static final int LOAD_DISSECTOR_LENGTH = LOAD_DISSECTOR.length(); private StructObjectInspector rowOI; private ArrayList row; private Parser parser; private ParsedRecord currentValue; // We do not want the parsing to fail immediately when we hit a single 'bad' line. // So we count the good and bad lines. // If we see more than 1% bad lines we abort (after we have seen 1000 lines) private static final long MINIMAL_FAIL_LINES = 1000; private static final int MINIMAL_FAIL_PERCENTAGE = 1; private long linesInput = 0; private long linesBad = 0; static class ColumnToGetterMapping { private int index; private Casts casts; private String fieldValue; } private final List columnToGetterMappings = new ArrayList<>(); @Override public void initialize(Configuration conf, Properties tableProperties, Properties partitionProperties) throws SerDeException { boolean usable = true; linesInput = 0; linesBad = 0; String logformat = tableProperties.getProperty("logformat"); Map> typeRemappings = new HashMap<>(); List additionalDissectors = new ArrayList<>(); for (Map.Entry property: tableProperties.entrySet()){ String key = (String)property.getKey(); if (key.startsWith(MAP_FIELD)) { String mapField = key.substring(MAP_FIELD_LENGTH); String mapType = (String)property.getValue(); Set remapping = typeRemappings.computeIfAbsent(mapField, k -> new HashSet<>()); remapping.add(mapType); LOG.info("Add mapping for field \"{}\" to type \"{}\"", mapField, mapType); continue; } if (key.startsWith(LOAD_DISSECTOR)) { String dissectorClassName = key.substring(LOAD_DISSECTOR_LENGTH); String dissectorParam = (String)property.getValue(); try { Class clazz = Class.forName(dissectorClassName); Constructor constructor = clazz.getConstructor(); Dissector instance = (Dissector) constructor.newInstance(); if (!instance.initializeFromSettingsParameter(dissectorParam)) { throw new SerDeException("Initialization failed of dissector instance of class " + dissectorClassName); } additionalDissectors.add(instance); } catch (ClassNotFoundException e) { throw new SerDeException("Found load with bad specification: No such class:" + dissectorClassName, e); } catch (NoSuchMethodException e) { throw new SerDeException("Found load with bad specification: Class does not have the required constructor", e); } catch (InvocationTargetException e) { throw new SerDeException("Got an InvocationTargetException", e); } catch (InstantiationException e) { throw new SerDeException("Got an InstantiationException", e); } catch (IllegalAccessException e) { throw new SerDeException("Found load with bad specification: Required constructor is not public", e); } LOG.debug("Loaded additional dissector: {}(\"{}\")", dissectorClassName, dissectorParam); } } currentValue = new ParsedRecord(); // List fieldList; int numColumns; String columnNameProperty = tableProperties.getProperty(serdeConstants.LIST_COLUMNS); String columnTypeProperty = tableProperties.getProperty(serdeConstants.LIST_COLUMN_TYPES); List columnNames = Arrays.asList(columnNameProperty.split(",")); List columnTypes = TypeInfoUtils.getTypeInfosFromTypeString(columnTypeProperty); assert columnNames.size() == columnTypes.size(); numColumns = columnNames.size(); parser = new HttpdLoglineParser<>(ParsedRecord.class, logformat); parser.setTypeRemappings(typeRemappings) .addDissectors(additionalDissectors); List columnOIs = new ArrayList<>(columnNames.size()); try { for (int columnNr = 0; columnNr < numColumns; columnNr++) { columnOIs.add(TypeInfoUtils.getStandardJavaObjectInspectorFromTypeInfo(columnTypes.get(columnNr))); String columnName = columnNames.get(columnNr); TypeInfo columnType = columnTypes.get(columnNr); String fieldValue = tableProperties.getProperty(FIELD + columnName); if (fieldValue == null) { LOG.error("MUST have Field value for column \"{}\".", columnName); usable = false; continue; } ColumnToGetterMapping ctgm = new ColumnToGetterMapping(); ctgm.index = columnNr; ctgm.fieldValue = fieldValue; List singleFieldValue= new ArrayList<>(); singleFieldValue.add(fieldValue); switch (columnType.getTypeName()) { case STRING_TYPE_NAME: ctgm.casts = STRING; parser.addParseTarget(ParsedRecord.class.getMethod("set", String.class, String.class), singleFieldValue); break; case BIGINT_TYPE_NAME: ctgm.casts = LONG; parser.addParseTarget(ParsedRecord.class.getMethod("set", String.class, Long.class), singleFieldValue); break; case DOUBLE_TYPE_NAME: ctgm.casts = DOUBLE; parser.addParseTarget(ParsedRecord.class.getMethod("set", String.class, Double.class), singleFieldValue); break; default: LOG.error("Requested column type {} is not supported at this time.", columnType.getTypeName()); usable = false; break; } columnToGetterMappings.add(ctgm); } } catch (NoSuchMethodException |SecurityException e) { throw new SerDeException("(Should not occur) Caught exception: {}", e); } // StandardStruct uses ArrayList to store the row. rowOI = ObjectInspectorFactory.getStandardStructObjectInspector(columnNames, columnOIs); // Constructing the row object, etc, which will be reused for all rows. row = new ArrayList<>(numColumns); for (int c = 0; c < numColumns; c++) { row.add(null); } if (!usable) { throw new SerDeException("Fatal config error. Check the logged error messages why."); } } @Override public ObjectInspector getObjectInspector() { return rowOI; } @Override public Object deserialize(Writable writable) throws SerDeException { if (!(writable instanceof Text)) { throw new SerDeException("The input MUST be a Text line."); } linesInput++; try { currentValue.clear(); parser.parse(currentValue, writable.toString()); } catch (DissectionFailure dissectionFailure) { linesBad++; if (linesInput >= MINIMAL_FAIL_LINES) { if (100* linesBad > MINIMAL_FAIL_PERCENTAGE * linesInput){ throw new SerDeException("To many bad lines: " + linesBad + " of " + linesInput + " are bad."); } } return null; // Just return that this line is nothing. } catch (InvalidDissectorException |MissingDissectorsException e) { throw new SerDeException("Cannot continue; Fix the Dissectors before retrying", e); } for (ColumnToGetterMapping ctgm: columnToGetterMappings) { switch(ctgm.casts) { case STRING: String currentValueString = currentValue.getString(ctgm.fieldValue); row.set(ctgm.index, currentValueString); break; case LONG: Long currentValueLong = currentValue.getLong(ctgm.fieldValue); row.set(ctgm.index, currentValueLong); break; case DOUBLE: Double currentValueDouble = currentValue.getDouble(ctgm.fieldValue); row.set(ctgm.index, currentValueDouble); break; default: // Do nothing } } return row; } @Override public Class getSerializedClass() { return null; // This is NOT a Serializer, ONLY a Deserializer! } @Override public SerDeStats getSerDeStats() { return new SerDeStats(); } } ================================================ FILE: httpdlog/httpdlog-serde/src/test/java/nl/basjes/parse/httpdlog/TestAllDissectorTypes.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.serde.serdeConstants; import org.apache.hadoop.hive.serde2.AbstractSerDe; import org.apache.hadoop.hive.serde2.SerDeException; import org.apache.hadoop.io.Text; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Properties; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; public class TestAllDissectorTypes { private static final Logger LOG = LoggerFactory.getLogger(TestAllDissectorTypes.class); @Test void testAllDissectorOutputTypes() throws Throwable { // Create the SerDe AbstractSerDe serDe = getTestSerDe(); // Data Text t = new Text("Doesn't matter"); // Deserialize Object row = serDe.deserialize(t); // ObjectInspector rowOI = serDe.getObjectInspector(); assertTrue(row instanceof List); @SuppressWarnings("unchecked") List rowArray = (List)row; LOG.debug("Deserialized row: {}", row); int index = -1; assertEquals("42", rowArray.get(++index)); // any_string assertEquals(42L, rowArray.get(++index)); // any_long assertEquals(42D, rowArray.get(++index)); // any_double assertEquals("FortyTwo", rowArray.get(++index)); // string_string assertEquals(null, rowArray.get(++index)); // string_long assertEquals(null, rowArray.get(++index)); // string_double assertEquals("42", rowArray.get(++index)); // int_string assertEquals(42L, rowArray.get(++index)); // int_long assertEquals(null, rowArray.get(++index)); // int_double assertEquals("42", rowArray.get(++index)); // long_string assertEquals(42L, rowArray.get(++index)); // long_long assertEquals(null, rowArray.get(++index)); // long_double assertEquals("42.0", rowArray.get(++index)); // float_string assertEquals(null, rowArray.get(++index)); // float_long assertEquals(42D, rowArray.get(++index)); // float_double assertEquals("42.0", rowArray.get(++index)); // double_string assertEquals(null, rowArray.get(++index)); // double_long assertEquals(42D, rowArray.get(++index)); // double_double } private AbstractSerDe getTestSerDe() throws SerDeException { // Create the SerDe Properties schema = new Properties(); schema.setProperty(serdeConstants.LIST_COLUMNS, "any_string," + "any_long," + "any_double," + "string_string," + "string_long," + "string_double," + "int_string," + "int_long," + "int_double," + "long_string," + "long_long," + "long_double," + "float_string," + "float_long," + "float_double," + "double_string," + "double_long," + "double_double" ); schema.setProperty(serdeConstants.LIST_COLUMN_TYPES, "string," + "bigint," + "double," + "string," + "bigint," + "double," + "string," + "bigint," + "double," + "string," + "bigint," + "double," + "string," + "bigint," + "double," + "string," + "bigint," + "double," ); schema.setProperty("logformat", "%t"); schema.setProperty("load:nl.basjes.parse.core.test.NormalValuesDissector", HttpdLogFormatDissector.INPUT_TYPE); schema.setProperty("field:any_string", "ANY:any"); schema.setProperty("field:any_long", "ANY:any"); schema.setProperty("field:any_double", "ANY:any"); schema.setProperty("field:string_string", "STRING:string"); schema.setProperty("field:string_long", "STRING:string"); schema.setProperty("field:string_double", "STRING:string"); schema.setProperty("field:int_string", "INT:int"); schema.setProperty("field:int_long", "INT:int"); schema.setProperty("field:int_double", "INT:int"); schema.setProperty("field:long_string", "LONG:long"); schema.setProperty("field:long_long", "LONG:long"); schema.setProperty("field:long_double", "LONG:long"); schema.setProperty("field:float_string", "FLOAT:float"); schema.setProperty("field:float_long", "FLOAT:float"); schema.setProperty("field:float_double", "FLOAT:float"); schema.setProperty("field:double_string", "DOUBLE:double"); schema.setProperty("field:double_long", "DOUBLE:double"); schema.setProperty("field:double_double", "DOUBLE:double"); AbstractSerDe serDe = new ApacheHttpdlogDeserializer(); serDe.initialize(new Configuration(), schema, null); return serDe; } } ================================================ FILE: httpdlog/httpdlog-serde/src/test/java/nl/basjes/parse/httpdlog/TestApacheHttpdlogDeserializer.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.httpdlog; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.serde.serdeConstants; import org.apache.hadoop.hive.serde2.AbstractSerDe; import org.apache.hadoop.hive.serde2.SerDeException; import org.apache.hadoop.io.Text; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Properties; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.fail; class TestApacheHttpdlogDeserializer { private static final Logger LOG = LoggerFactory.getLogger(TestApacheHttpdlogDeserializer.class); private final String logformat = "%h %a %A %l %u %t \"%r\" " + "%>s %b %p \"%q\" \"%{Referer}i\" %D \"%{User-agent}i\" " + "\"%{Cookie}i\" " + "\"%{Set-Cookie}o\" " + "\"%{If-None-Match}i\" \"%{Etag}o\""; private final String testLogLine = "127.0.0.1 127.0.0.1 127.0.0.1 - - [24/Oct/2012:23:00:44 +0200] \"GET /index.php?s=800x600 HTTP/1.1\" " + "200 - 80 \"\" \"-\" 80991 \"Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0\" " + "\"jquery-ui-theme=Eggplant; Apache=127.0.0.1.1351111543699529\" " + "\"" + "NBA-1=1234, " + "NBA-2=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT, " + "NBA-3=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/, " + "NBA-4=1234; expires=Wed, 01-Jan-2020 00:00:10 GMT; path=/; domain=.basj.es" + "\" \"-\" \"-\""; @Test void testBasicParse() throws Throwable { // Create the SerDe AbstractSerDe serDe = getTestSerDe(); // Data Text t = new Text(testLogLine); // Deserialize Object row = serDe.deserialize(t); if (!(row instanceof List)) { fail("row must be instanceof List<>"); } List rowArray = (List)row; LOG.debug("Deserialized row: {}", row); assertEquals("127.0.0.1", rowArray.get(0)); assertEquals(1351112444000L, rowArray.get(1)); assertEquals("Mozilla/5.0 (X11; Linux i686 on x86_64; rv:11.0) Gecko/20100101 Firefox/11.0", rowArray.get(2)); assertEquals(800L, rowArray.get(3)); assertEquals(600L, rowArray.get(4)); } @Test void testHighFailRatio1() throws Throwable { AbstractSerDe serDe = getTestSerDe(); // Data Text goodLine = new Text(testLogLine); Text badLine = new Text("A really bad line"); Object row; // Deserialize good line row = serDe.deserialize(goodLine); assertNotNull(row); // Deserialize bad line row = serDe.deserialize(badLine); assertNull(row); for (int i = 0; i < 999; i++) { // Deserialize good line row = serDe.deserialize(goodLine); assertNotNull(row); } assertThrows(SerDeException.class, () -> { Object extraRow; for (int i = 0; i < 99; i++) { // Deserialize bad line extraRow = serDe.deserialize(badLine); assertNull(extraRow); } }); } private AbstractSerDe getTestSerDe() throws SerDeException { // Create the SerDe Properties schema = new Properties(); schema.setProperty(serdeConstants.LIST_COLUMNS, "ip,timestamp,useragent,screenWidth,screenHeight"); schema.setProperty(serdeConstants.LIST_COLUMN_TYPES, "string,bigint,string,bigint,bigint"); schema.setProperty("logformat", logformat); schema.setProperty("field:timestamp", "TIME.EPOCH:request.receive.time.epoch"); schema.setProperty("field:ip", "IP:connection.client.host"); schema.setProperty("field:useragent", "HTTP.USERAGENT:request.user-agent"); schema.setProperty("load:nl.basjes.parse.httpdlog.dissectors.ScreenResolutionDissector", "x"); schema.setProperty("map:request.firstline.uri.query.s", "SCREENRESOLUTION"); schema.setProperty("field:screenWidth", "SCREENWIDTH:request.firstline.uri.query.s.width"); schema.setProperty("field:screenHeight", "SCREENHEIGHT:request.firstline.uri.query.s.height"); AbstractSerDe serDe = new ApacheHttpdlogDeserializer(); serDe.initialize(new Configuration(), schema, null); return serDe; } } ================================================ FILE: httpdlog/httpdlog-serde/src/test/resources/log4j.properties ================================================ # # Apache HTTPD & NGINX Access log parsing made easy # Copyright (C) 2011-2023 Niels Basjes # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Root logger option log4j.rootLogger=INFO, stdout #, file log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.threshold=INFO log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n ## file appender #log4j.appender.file=org.apache.log4j.RollingFileAppender #log4j.appender.file.File=target/debug.log #log4j.appender.file.threshold=DEBUG #log4j.appender.file.layout=org.apache.log4j.PatternLayout #log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n #log4j.appender.file.Append=false ================================================ FILE: httpdlog/pom.xml ================================================ 4.0.0 parser-parent nl.basjes.parse 6.0.1-SNAPSHOT nl.basjes.parse.httpdlog httpdlog pom Parser - Apache HTTPD - httpdlog-parser httpdlog-inputformat httpdlog-serde org.apache.maven.plugins maven-checkstyle-plugin ================================================ FILE: parser-core/pom.xml ================================================ 4.0.0 parser-parent nl.basjes.parse 6.0.1-SNAPSHOT parser-core Parser - Core org.apache.maven.plugins maven-checkstyle-plugin org.jacoco jacoco-maven-plugin nl/basjes/parse/core/Field.class nl/basjes/parse/core/exceptions/*.class org.apache.maven.plugins maven-jar-plugin test-jar ================================================ FILE: parser-core/src/main/assembly/job.xml ================================================ job jar false false lib false compile ${project.build.outputDirectory} ${file.separator} ================================================ FILE: parser-core/src/main/java/nl/basjes/parse/core/Casts.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.core; import java.util.EnumSet; public enum Casts { STRING, LONG, DOUBLE; public static final EnumSet NO_CASTS = EnumSet.noneOf(Casts.class); public static final EnumSet STRING_ONLY = EnumSet.of(STRING); public static final EnumSet LONG_ONLY = EnumSet.of(LONG); public static final EnumSet DOUBLE_ONLY = EnumSet.of(DOUBLE); public static final EnumSet STRING_OR_LONG = EnumSet.of(STRING, LONG); public static final EnumSet STRING_OR_DOUBLE = EnumSet.of(STRING, DOUBLE); public static final EnumSet STRING_OR_LONG_OR_DOUBLE = EnumSet.of(STRING, LONG, DOUBLE); } ================================================ FILE: parser-core/src/main/java/nl/basjes/parse/core/Dissector.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.core; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.EnumSet; import java.util.List; /** *

A Dissector is a class capable of chopping a String into multiple values of specific types.

*

The lifecycle:

*

Parser setup

*
    *
  1. First instance is constructed
  2. *
  3. First instance is added to the {@link nl.basjes.parse.core.Parser} using * {@link nl.basjes.parse.core.Parser#addDissector(Dissector)}
  4. *
  5. The {@link nl.basjes.parse.core.Parser} calls {@link #getInputType()} and {@link #getPossibleOutput()} to know * what this dissector can deliver.
  6. *
*

The parser now constructs a tree based on the available {@link Dissector}s * and what was requested.

*

Dissectors setup

*

For each node in the tree a new instance of the required dissector is created by calling {@link #getNewInstance()} * which calls {@link #initializeNewInstance(Dissector)}. Note that only {@link Dissector}s * that are actually needed will be in the parse tree.

*

For each of those instances in the tree:

*
    *
  1. For each of the actually needed input+output combinations {@link #prepareForDissect(String, String)} is called. * This can be used to avoid needless CPU cycles during the actual run.
  2. *
  3. As a final step a call to {@link #prepareForRun()} is done as an indication that all preparation input has been * provided. A Dissector can use this to finalize the runtime data structures so doing the actual dissecting faster.
  4. *
*

Dissecting

*
    *
  • During a run the instance will be called with {@link #dissect} many times.
  • *
  • In the {@link #dissect(Parsable, String)} the actual value to be worked on must be retrieved using * {@link nl.basjes.parse.core.Parsable#getParsableField(String, String)}
  • *
  • The result(s) of the dissection must be put back using * {@link nl.basjes.parse.core.Parsable#addDissection(String, String, String, String)}
  • *
*/ public abstract class Dissector implements Serializable { private static final Logger LOG = LoggerFactory.getLogger(Dissector.class); // -------------------------------------------- /** * If a Dissector is loaded through an external language then this is the * method that is called to set all the parameters. * There is exactly one String as input so it is up to the specific * Dissector implementation to parse and handle this input. * @return true if everything went right. false otherwise. */ public boolean initializeFromSettingsParameter(String settings) { // Default behaviour is to do nothing. return true; } // -------------------------------------------- /** * This method must dissect the provided field from the parsable into 'smaller' pieces. */ public abstract void dissect(Parsable parsable, String inputname) throws DissectionFailure; // -------------------------------------------- /** * @return The required typename of the input */ public abstract String getInputType(); // -------------------------------------------- /** * What are all possible outputs that can be provided. * @return List of "type:name" values that indicates all the possible outputs. Never a null! */ public abstract List getPossibleOutput(); // -------------------------------------------- /** * This tells the dissector that it should prepare that we will call it soon * with 'inputname' and expect to get 'inputname.outputname' because * inputname is of the type returned by getInputType and outputname * was part of the answer from getPossibleOutput. * This can be used by the dissector implementation to optimize the internal parsing * algorithms and lookup tables and such. * The dissector must return the types to which this value can be mapped later on during the run. * @return The EnumSet of all allowed casts. Returns an empty EnumSet if nothing is allowed. Never a null ! */ public abstract EnumSet prepareForDissect(String inputname, String outputname); // -------------------------------------------- /** * The framework will tell the dissector that it should get ready to run. * I.e. finalize the bootstrapping. */ public void prepareForRun() throws InvalidDissectorException { // Default behaviour is do nothing. } // -------------------------------------------- /** * Create an additional instance of this dissector. * This is needed because in the parse tree we may need the same dissector multiple times. * In order to optimize per node we need separate instances. * @return New instance of this Dissector */ public Dissector getNewInstance() throws InvalidDissectorException { try { Constructor co = this.getClass().getConstructor(); Dissector newInstance = co.newInstance(); initializeNewInstance(newInstance); return newInstance; } catch (Exception e) { String error = "Unable to create instance of " + this.getClass().getCanonicalName() + ": " + e.getClass().getSimpleName() + ": " + e.getMessage(); LOG.error("{}", error); throw new InvalidDissectorException(error, e); } } public String extractFieldName(final String inputname, final String outputname){ String fieldName = outputname; if (inputname.equals(outputname)) { return ""; } if (!inputname.equals("")) { fieldName = outputname.substring(inputname.length() + 1); } return fieldName; } /** * This is called after instantiating the class that is actually in the parsetree. * @param newInstance The new instances of this class that must be initialized */ protected void initializeNewInstance(Dissector newInstance) throws InvalidDissectorException { // Default behaviour is do nothing. } /** * If a dissector really needs to add an additional dissector to the set this method is the * place to do so. * @param parser The instance of the parser where the extra dissector is to be added to. * @param The type of the record. */ public void createAdditionalDissectors(Parser parser) { // Default behaviour is do nothing. } public void setInputType(String s) throws InvalidDissectorException { // Usually only implemented in very dynamic dissectors (like custom timestamp format) throw new InvalidDissectorException("The InputType of " + this.getClass().getCanonicalName() + " cannot be changed"); } @Override public String toString() { return "{ " + this.getClass().getSimpleName() + " : " + getInputType() + " --> " + getPossibleOutput() + " }"; } } ================================================ FILE: parser-core/src/main/java/nl/basjes/parse/core/Field.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.core; import nl.basjes.parse.core.Parser.SetterPolicy; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) /* * Defines the source field that must be used to call this setter. */ public @interface Field { String[] value(); SetterPolicy setterPolicy() default SetterPolicy.ALWAYS; } ================================================ FILE: parser-core/src/main/java/nl/basjes/parse/core/Parsable.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.core; import nl.basjes.parse.core.exceptions.DissectionFailure; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.TreeMap; public final class Parsable { private static final Logger LOG = LoggerFactory.getLogger(Parsable.class); private final Parser parser; // The actual record for which all the information is intended. private final RECORD record; // This caches the values and intermediate values private final Map cache = new TreeMap<>(); // The end nodes we really need as output // Values look like "TYPE:foo.bar" private final Set needed; // Values look like "TYPE:foo.bar" private final Set usefulIntermediates; // The set of ParsedFields that need to be parsed further private final Set toBeParsed = new HashSet<>(); private final Map> typeRemappings; // -------------------------------------------- public Parsable(final Parser parser, final RECORD record, Map> typeRemappings) { this.parser = parser; this.record = record; this.typeRemappings = typeRemappings; needed = parser.getNeeded(); usefulIntermediates = parser.getUsefulIntermediateFields(); } // -------------------------------------------- /** Store a newly parsed value in the result set */ void setRootDissection(final String type, final String value) { LOG.debug("Got root dissection: type={}", type); // The root name is an empty string final ParsedField parsedfield = new ParsedField(type, "", value); cache.put(parsedfield.getId(), parsedfield); toBeParsed.add(parsedfield); } // -------------------------------------------- /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final int value) throws DissectionFailure { LOG.debug("Got new (int) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, new Value((long)value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final Integer value) throws DissectionFailure { LOG.debug("Got new (Integer) dissection: base={}; type={}; name=\"{}\"", base, type, name); if (value == null) { return addDissection(base, type, name, new Value((Long)null), false); } return addDissection(base, type, name, new Value((long)value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final long value) throws DissectionFailure { LOG.debug("Got new (long) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, new Value(value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final Long value) throws DissectionFailure { LOG.debug("Got new (Long) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, new Value(value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final float value) throws DissectionFailure { LOG.debug("Got new (float) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, new Value((double)value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final Float value) throws DissectionFailure { LOG.debug("Got new (Float) dissection: base={}; type={}; name=\"{}\"", base, type, name); if (value == null) { return addDissection(base, type, name, new Value((Double)null), false); } return addDissection(base, type, name, new Value((double)value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final double value) throws DissectionFailure { LOG.debug("Got new (double) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, new Value(value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final Double value) throws DissectionFailure { LOG.debug("Got new (Double) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, new Value(value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final String value) throws DissectionFailure { LOG.debug("Got new (String) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, new Value(value), false); } /** Store a newly parsed value in the result set */ public Parsable addDissection(final String base, final String type, final String name, final Value value) throws DissectionFailure { LOG.debug("Got new (Value) dissection: base={}; type={}; name=\"{}\"", base, type, name); return addDissection(base, type, name, value, false); } private Parsable addDissection( final String base, final String type, final String name, final Value value, final boolean recursion) throws DissectionFailure { String completeName; String neededWildCardName; if (base.isEmpty()) { // The root name is an empty string completeName = name; neededWildCardName = type + ':' + "*"; } else { if (name.isEmpty()) { completeName = base; } else { completeName = base + '.' + name; } neededWildCardName = type + ':' + base + ".*"; } String neededName = type + ':' + completeName; if (!recursion) { if (typeRemappings.containsKey(completeName)) { Set typeRemappingSet = typeRemappings.get(completeName); for (String typeRemapping : typeRemappingSet) { if (type.equals(typeRemapping)) { throw new DissectionFailure( "[Type Remapping] Trying to map to the same type (mapping definition bug!): " + " base=" + base + " type=" + type + " name=" + name); } addDissection(base, typeRemapping, name, value, true); } } } final ParsedField parsedfield = new ParsedField(type, completeName, value); if (usefulIntermediates.contains(completeName)) { cache.put(parsedfield.getId(), parsedfield); toBeParsed.add(parsedfield); } if (needed.contains(neededName)) { parser.store(record, neededName, neededName, value); } if (needed.contains(neededWildCardName)) { parser.store(record, neededWildCardName, neededName, value); } return this; } // -------------------------------------------- public ParsedField getParsableField(final String type, final String name) { return cache.get(ParsedField.makeId(type, name)); } // -------------------------------------------- public RECORD getRecord() { return record; } // -------------------------------------------- public void setAsParsed(final ParsedField parsedField) { toBeParsed.remove(parsedField); } // -------------------------------------------- public Set getToBeParsed() { return toBeParsed; } } ================================================ FILE: parser-core/src/main/java/nl/basjes/parse/core/ParsedField.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.core; public class ParsedField { private final String type; private final String name; private final Value value; public ParsedField(String type, String name, Value value) { this.type = type; this.name = name; if (value==null) { this.value = new Value((String)null); } else { this.value = value; } } public ParsedField(String type, String name, String value) { this.type = type; this.name = name; this.value = new Value(value); } public String getType() { return type; } public String getName() { return name; } public Value getValue() { return value; } public static String makeId(String type, String name) { return type+':'+name; } public String getId() { return makeId(type, name); } public String toString(){ return getId() + " = " + value; } } ================================================ FILE: parser-core/src/main/java/nl/basjes/parse/core/Parser.java ================================================ /* * Apache HTTPD & NGINX Access log parsing made easy * Copyright (C) 2011-2023 Niels Basjes * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package nl.basjes.parse.core; import nl.basjes.parse.core.exceptions.DissectionFailure; import nl.basjes.parse.core.exceptions.FatalErrorDuringCallOfSetterMethod; import nl.basjes.parse.core.exceptions.InvalidDissectorException; import nl.basjes.parse.core.exceptions.InvalidFieldMethodSignature; import nl.basjes.parse.core.exceptions.MissingDissectorsException; import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.stream.Collectors; import static nl.basjes.parse.core.Casts.STRING_ONLY; import static nl.basjes.parse.core.Parser.SetterPolicy.ALWAYS; import static nl.basjes.parse.core.Parser.SetterPolicy.NOT_EMPTY; import static nl.basjes.parse.core.Parser.SetterPolicy.NOT_NULL; public class Parser implements Serializable { public enum SetterPolicy { /** Call the setter for all values: Normal, Empty and NULL */ ALWAYS, /** Call the setter for values: Normal and Empty, but not for NULL values */ NOT_NULL, /** Call the setter for values: Normal, but not for Empty and NULL values */ NOT_EMPTY } private static class DissectorPhase implements Serializable { DissectorPhase(final String inputType, final String outputType, final String name, final Dissector instance) { this.inputType = inputType; this.outputType = outputType; this.name = name; this.instance = instance; } private final String inputType; private final String outputType; private final String name; private final Dissector instance; } // -------------------------------------------- private static final Logger LOG = LoggerFactory.getLogger(Parser.class); private final Class recordClass; private final Set availableDissectors = new HashSet<>(); private final Set allDissectors = new HashSet<>(); // Key = "request.time.hour" // Value = the set of dissectors that must all be started once we have this value private HashMap> compiledDissectors = null; private HashSet usefulIntermediateFields = null; private String rootType; // NOTE: The Method is NOT serializable. So after deserialization the 'assembled' is false // and we 're-find' all methods using their names and parameter lists. // The target methods in the record class that will want to receive the values private transient Map>> targets = new TreeMap<>(); // Each method is a list of String: method name followed by the class names of each parameter. private final Map, SetterPolicy>>> targetsMethodNames = new TreeMap<>(); private transient boolean assembled = false; private final Map> castsOfTargets = new TreeMap<>(); // -------------------------------------------- public Set getNeeded() { return targets.keySet(); } /** * Returns the casts possible for the specified path. * Before you call 'getCasts' the actual parser needs to be constructed. * Simply calling getPossiblePaths does not build the actual parser. * If you want to get the casts for all possible paths the code looks something like this: *
{@code
     * Parser dummyParser= new HttpdLoglineParser<>(Object.class, logformat);
     * List possiblePaths = dummyParser.getPossiblePaths();
     * // Use a random method that has the right signature
     * dummyParser.addParseTarget(String.class.getMethod("indexOf", String.class), possiblePaths);
     * for (String path : possiblePaths) {
     *     LOG.info("{}     {}", path, dummyParser.getCasts(path));
     * }
     * }
     * @param name The name of the path for which you want the casts
     * @return The set of casts that are valid for this name. Null if this name is unknown.
     */
    public EnumSet getCasts(String name) throws MissingDissectorsException, InvalidDissectorException {
        assembleDissectors();
        return castsOfTargets.get(name);
    }

    public Map> getAllCasts() throws MissingDissectorsException, InvalidDissectorException {
        assembleDissectors();
        return castsOfTargets;
    }

    // --------------------------------------------

    Set getUsefulIntermediateFields() {
        return usefulIntermediateFields;
    }

    // --------------------------------------------

    public final Parser addDissectors(final List dissectors) {
        assembled = false;
        if (dissectors != null) {
            allDissectors.addAll(dissectors);
        }
        return this;
    }

    // --------------------------------------------

    public final Parser addDissector(final Dissector dissector) {
        assembled = false;
        if (dissector != null) {
            allDissectors.add(dissector);
        }
        return this;
    }

    // --------------------------------------------

    public final Parser dropDissector(Class dissectorClassToDrop) {
        assembled = false;
        Set removeDissector = new HashSet<>();
        for (final Dissector dissector : allDissectors) {
            if (dissector.getClass().equals(dissectorClassToDrop)) {
                removeDissector.add(dissector);
            }
        }
        allDissectors.removeAll(removeDissector);
        return this;
    }

    // --------------------------------------------

    public final Set getAllDissectors() {
        return allDissectors;
    }

    // --------------------------------------------

    public Parser setRootType(final String newRootType) {
        assembled = false;
        rootType = newRootType;
        return this;
    }

    // --------------------------------------------
    private void assembleDissectorPhases() throws InvalidDissectorException {
        availableDissectors.clear();
        for (final Dissector dissector : allDissectors) {
            final String inputType = dissector.getInputType();
            if (inputType == null) {
                throw new InvalidDissectorException("Dissector returns null on getInputType(): ["+ dissector.getClass().getCanonicalName()+"]");
            }

            final List outputs = dissector.getPossibleOutput();
            if (outputs == null || outputs.isEmpty()) {
                throw new InvalidDissectorException("Dissector cannot create any outputs: ["+ dissector.getClass().getCanonicalName()+"]");
            }

            // Create all dissector phases
            for (final String output: outputs) {
                final int colonPos = output.indexOf(':');
                final String outputType = output.substring(0, colonPos);
                final String name = output.substring(colonPos + 1);
                availableDissectors.add(new DissectorPhase(inputType, outputType, name, dissector));
            }
        }
    }

    // --------------------------------------------

    private boolean failOnMissingDissectors = true;

    /**
     * This method sets the flag to ignore the missing dissectors situation.
     * This must be called before parsing the first line.
     * The effect is that those fields that would have been classified as 'missing'
     * will result in a null value (or better: the setter is never called) for all records.
     */
    public Parser ignoreMissingDissectors() {
        failOnMissingDissectors = false;
        return this;
    }

    /**
     * Reset back to the default of failing on missing dissectors.
     */
    public Parser failOnMissingDissectors() {
        failOnMissingDissectors = true;
        return this;
    }


    private void assembleDissectors() throws MissingDissectorsException, InvalidDissectorException {
        if (assembled) {
            return; // nothing to do.
        }

        if (targets == null) {
            // This happens only AFTER deserialization.
            targets = new HashMap<>(targetsMethodNames.size());

            for (Entry, SetterPolicy>>> entry:targetsMethodNames.entrySet()) {

                String fieldName = entry.getKey();
                Set, SetterPolicy>> methodSet = entry.getValue();

                Set> fieldTargets = targets.computeIfAbsent(fieldName, k -> new HashSet<>());

                for(Pair, SetterPolicy> methodStringPair: methodSet) {
                    List methodString = methodStringPair.getLeft();
                    SetterPolicy setterPolicy = methodStringPair.getRight();
                    Method method;
                    String methodName = methodString.get(0);
                    int numberOfParameters = methodString.size()-1;
                    Class[] parameters = new Class[numberOfParameters];
                    try {
                        parameters[0] = Class.forName(methodString.get(1));
                        if (numberOfParameters == 2) {
                            parameters[1] = Class.forName(methodString.get(2));
                        }
                    } catch (ClassNotFoundException e) {
                        throw new InvalidDissectorException("Unable to locate class", e);
                    }
                    try {
                        method = recordClass.getMethod(methodName, parameters);
                        fieldTargets.add(Pair.of(method, setterPolicy));
                    } catch (NoSuchMethodException e) {
                        throw new InvalidDissectorException("Unable to locate method " + methodName, e);
                    }
                }
                targets.put(fieldName, fieldTargets);
            }
        }

        // In some cases a dissector may need to create a special 'extra' dissector.
        // Which in some cases this is a recursive problem
        Set doneDissectors = new HashSet<>(allDissectors.size() + 10);
        Set loopDissectors = new HashSet<>(allDissectors);

        while (!loopDissectors.isEmpty()) {
            for (final Dissector dissector : loopDissectors) {
                dissector.createAdditionalDissectors(this);
            }
            doneDissectors.addAll(loopDissectors);
            loopDissectors.clear();
            loopDissectors.addAll(allDissectors);
            loopDissectors.removeAll(doneDissectors);
        }

        // So
        // - we have a set of needed values (targets)
        // - we have a set of dissectors that can pick apart some input
        // - we know where to start from
        // - we need to know how to proceed

        assembleDissectorPhases();

        // Step 1: Acquire all potentially useful subtargets
        // We first build a set of all possible subtargets that may be useful
        // this way we can skip anything we know not to be useful
        Set needed = new HashSet<>(getNeeded());
        needed.add(rootType + ':'); // The root name is an empty string
        LOG.debug("Root: >>>{}:<<<", rootType);

        Set allPossibleSubtargets = new HashSet<>();
        for (String need : needed) {
            String neededName = need.substring(need.indexOf(':') + 1);
            LOG.debug("Needed  : >>>{}<<<", neededName);
            String[] needs = neededName.split("\\.");
            StringBuilder sb = new StringBuilder(need.length());

            for (String part : needs) {
                if (sb.length() == 0 || part.length() == 0) {
                    sb.append(part);
                } else {
                    sb.append('.').append(part);
                }
                allPossibleSubtargets.add(sb.toString());
                LOG.debug("Possible: >>>{}<<<", sb);
            }
        }

        // Step 2: From the root we explore all possibly useful trees (recursively)
        compiledDissectors = new HashMap<>();
        usefulIntermediateFields = new HashSet<>();
        Set locatedTargets = new HashSet<>();
        findUsefulDissectorsFromField(allPossibleSubtargets, locatedTargets, rootType, "", true); // The root name is an empty string

        // Step 3: Inform all dissectors to prepare for the run
        for (Set dissectorPhases : compiledDissectors.values()) {
            for (DissectorPhase dissectorPhase : dissectorPhases) {
                dissectorPhase.instance.prepareForRun();
            }
        }

        if (compiledDissectors == null || compiledDissectors.isEmpty()) {
            throw new MissingDissectorsException("There are no dissectors at all which makes this a completely useless parser.");
        }

        if (failOnMissingDissectors) {
            // Step 4: As a final step we verify that every required input can be found
            Set missingDissectors = getTheMissingFields(locatedTargets);
            if (!missingDissectors.isEmpty()) {
                StringBuilder allMissing = new StringBuilder(missingDissectors.size() * 64);
                for (String missing : missingDissectors) {
                    allMissing.append('\n').append(missing);
                }
                throw new MissingDissectorsException(allMissing.toString());
            }
        }
        assembled = true;
    }

    // --------------------------------------------

    private void findUsefulDissectorsFromField(
            final Set possibleTargets,
            final Set locatedTargets,
            final String subRootType, final String subRootName,
            final boolean thisIsTheRoot) throws InvalidDissectorException {

        String subRootId = subRootType + ':' + subRootName;

        // When we reach this point we have dissectors to get here.
        // So we store this to later validate if we have everything.
        if (locatedTargets.contains(subRootId)) {
            // We already found this one.
            return; // Avoid infinite recursion
        }
        locatedTargets.add(subRootId);

        LOG.debug("findUsefulDissectors:\"{}\" \"{}\"", subRootType, subRootName);

        for (DissectorPhase dissector: availableDissectors) {

            if (!(dissector.inputType.equals(subRootType))) {
                continue; // Wrong type
            }

            // If it starts with a . it extends.
            // If it doesn't then it starts at the beginning
            Set checkFields = new HashSet<>();

            // If true then this dissector can output any name instead of just one
            boolean isWildCardDissector = dissector.name.equals("*");

            if (isWildCardDissector) {
                // Ok, this is special
                // We need to see if any of the wanted types start with the
                // subRootName (it may have a '.' in the rest of the line !)
                String subRootNameMatch = subRootName + '.';
                for (String possibleTarget : possibleTargets) {
                    if (possibleTarget.startsWith(subRootNameMatch)) {
                        checkFields.add(possibleTarget);
                    }
                }
            } else if (thisIsTheRoot) {
                checkFields.add(dissector.name);
            } else if (dissector.name.isEmpty()) {
                checkFields.add(subRootName);
            } else {
                checkFields.add(subRootName + '.' + dissector.name);
            }

            for (String checkField: checkFields) {
                if (possibleTargets.contains(checkField)
                    && !compiledDissectors.containsKey(dissector.outputType + ":" + checkField)) {

                    Set subRootPhases = compiledDissectors.get(subRootId);
                    if (subRootPhases == null) {
                        // New so we can simply add it.
                        subRootPhases = new HashSet<>();
                        compiledDissectors.put(subRootId, subRootPhases);
                        usefulIntermediateFields.add(subRootName);
                    }

                    Class clazz = dissector.instance.getClass();
                    DissectorPhase dissectorPhaseInstance = findDissectorInstance(subRootPhases, clazz);

                    if (dissectorPhaseInstance == null) {
                        dissectorPhaseInstance =
                                new DissectorPhase(dissector.inputType, dissector.outputType,
                                        checkField, dissector.instance.getNewInstance());
                        subRootPhases.add(dissectorPhaseInstance);
                    }

                    // Tell the dissector instance what to expect
                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Informing : ({}){} --> {} --> ({}){}",
                                dissector.inputType, subRootName,
                                dissector.instance.getClass().getName(),
                                dissector.outputType, checkField);
                    }
                    castsOfTargets.put(dissector.outputType + ':' + checkField,
                            dissectorPhaseInstance.instance.prepareForDissect(subRootName, checkField));

                    // Recurse from this point down
                    findUsefulDissectorsFromField(possibleTargets, locatedTargets, dissector.outputType, checkField, false);
                }
            }
        }

        Set mappings = typeRemappings.get(subRootName);
        if (mappings != null) {
            for (String mappedType : mappings) {
                if (!compiledDissectors.containsKey(mappedType + ':' + subRootName)) {
                    // Retyped targets are ALWAYS String ONLY if they do not yet exist.
                    castsOfTargets.putIfAbsent(mappedType + ':' + subRootName, STRING_ONLY);
                    findUsefulDissectorsFromField(possibleTargets, locatedTargets, mappedType, subRootName, false);
                }
            }
        }

    }

    private DissectorPhase findDissectorInstance(Set dissectorPhases,
                                                 Class clazz) {
        for (DissectorPhase phase : dissectorPhases) {
            if (phase.instance.getClass() == clazz) {
                return phase;
            }
        }
        return null;
    }

    // --------------------------------------------

    private Set getTheMissingFields(Set locatedTargets) {
        Set missing = new HashSet<>();
        for (String target : getNeeded()) {
            if (!locatedTargets.contains(target)) {
                // Handle wildcard targets differently
                if (target.endsWith("*")) {
                    if (target.endsWith(".*")) {
                        if (!locatedTargets.contains(target.substring(0, target.length() - 2))) {
                            missing.add(target);
                        }
                    }
                    // Else: it ends with :* and it is always "present".
                } else {
                    missing.add(target);
                }
            }
        }
        return missing;
    }

    // --------------------------------------------

    /*
     * The constructor tries to retrieve the desired fields from the annotations in the specified class. */
    public Parser(final Class clazz) {
        recordClass = clazz;

        // Get all methods of the correct signature that have been annotated
        // with Field
        for (final Method method : recordClass.getMethods()) {
            final Field field = method.getAnnotation(Field.class);
            if (field != null) {
                addParseTarget(method, field.setterPolicy(), Arrays.asList(field.value()));
            }
        }
    }

    // --------------------------------------------

    /*
     * When there is a need to add a target callback manually use this method. */
    public Parser addParseTarget(final String setterMethodName,
                               final String fieldValue) throws NoSuchMethodException {
        addParseTarget(setterMethodName, ALWAYS, fieldValue);
        return this;
    }

    /*
     * When there is a need to add a target callback manually use this method. */
    public Parser addParseTarget(final String setterMethodName,
                               final SetterPolicy setterPolicy,
                               final String fieldValue) throws NoSuchMethodException {
        Method method;

        try {
            method = recordClass.getMethod(setterMethodName, String.class);
        } catch (NoSuchMethodException a) {
            try {
                method = recordClass.getMethod(setterMethodName, String.class, String.class);
            } catch (NoSuchMethodException b) {
                try {
                    method = recordClass.getMethod(setterMethodName, String.class, Long.class);
                } catch (NoSuchMethodException c) {
                    try {
                        method = recordClass.getMethod(setterMethodName, String.class, Double.class);
                    } catch (NoSuchMethodException d) {
                        try {
                            method = recordClass.getMethod(setterMethodName, Long.class);
                        } catch (NoSuchMethodException e) {
                            try {
                                method = recordClass.getMethod(setterMethodName, Double.class);
                            } catch (NoSuchMethodException f) {
                                throw new NoSuchMethodException(
                                    "Unable to find any valid form of the method " + setterMethodName +
                                        " in the class " + recordClass.getCanonicalName());
                            }
                        }
                    }
                }
            }
        }

        addParseTarget(method, setterPolicy, Collections.singletonList(fieldValue));
        return this;
    }


    /*
     * When there is a need to add a target callback manually use this method. */
    public Parser addParseTarget(final Method method, final String fieldValue) {
        return addParseTarget(method, SetterPolicy.ALWAYS, Collections.singletonList(fieldValue));
    }

    /*
     * When there is a need to add a target callback manually use this method. */
    public Parser addParseTarget(final Method method,
                               final SetterPolicy setterPolicy,
                               final String fieldValue) {
        return addParseTarget(method, setterPolicy, Collections.singletonList(fieldValue));
    }

    /*
     * When there is a need to add a target callback manually use this method. */
    public Parser addParseTarget(final Method method, final List fieldValues) {
        return addParseTarget(method, SetterPolicy.ALWAYS, fieldValues);
    }

    /*
     * When there is a need to add a target callback manually use this method. */
    public Parser addParseTarget(final Method method,
                               final SetterPolicy setterPolicy,
                               final List fieldValues) {
        assembled = false;

        if (method == null || fieldValues == null) {
            return this; // Nothing to do here
        }

        final Class[] parameters = method.getParameterTypes();
        if (
                // Setters that receive a String
                ((parameters.length == 1) && (parameters[0] == String.class)) ||
                ((parameters.length == 2) && (parameters[0] == String.class) && (parameters[1] == String.class)) ||

                // Setters that receive a Long
                ((parameters.length == 1) && (parameters[0] == Long.class)) ||
                ((parameters.length == 2) && (parameters[0] == String.class) && (parameters[1] == Long.class)) ||

                // Setters that receive a Double
                ((parameters.length == 1) && (parameters[0] == Double.class)) ||
                ((parameters.length == 2) && (parameters[0] == String.class) && (parameters[1] == Double.class))
        ) {
            for (final String fieldValue : fieldValues) {
                if (fieldValue == null) {
                    continue;
                }
                String cleanedFieldValue = cleanupFieldValue(fieldValue);
                if (!fieldValue.equals(cleanedFieldValue)) {
                    LOG.warn("The requested \"{}\" was converted into \"{}\"", fieldValue, cleanedFieldValue);
                }

                // We have 1 real target
                Set> fieldTargets = targets.computeIfAbsent(cleanedFieldValue, k -> new HashSet<>());
                fieldTargets.add(Pair.of(method, setterPolicy));
                targets.put(cleanedFieldValue, fieldTargets);

                // We have 1 real target
                Set, SetterPolicy>> fieldTargetNames = targetsMethodNames.get(cleanedFieldValue);
                if (fieldTargetNames == null) {
                    fieldTargetNames = new HashSet<>();
                }
                List methodList = new ArrayList<>();
                methodList.add(method.getName());
                for (Class clazz: method.getParameterTypes()) {
                    methodList.add(clazz.getCanonicalName());
                }
                fieldTargetNames.add(Pair.of(methodList, setterPolicy));
                targetsMethodNames.put(cleanedFieldValue, fieldTargetNames);
            }
        } else {
            throw new InvalidFieldMethodSignature(method);
        }
        return this;
    }

    // --------------------------------------------

    private Map> typeRemappings = new HashMap<>(16);

    public Parser setTypeRemappings(Map> pTypeRemappings) {
        if (pTypeRemappings == null) {
            this.typeRemappings.clear();
        } else {
            this.typeRemappings = pTypeRemappings;
        }
        return this;
    }

    public Parser addTypeRemappings(Map> additionalTypeRemappings) {
        for (Entry> entry: additionalTypeRemappings.entrySet()){
            String input = entry.getKey();
            for (String newType: entry.getValue()) {
                addTypeRemapping(input, newType, STRING_ONLY);
            }
        }
        return this;
    }

    public Parser addTypeRemapping(String input, String newType) {
        return addTypeRemapping(input, newType, STRING_ONLY);
    }

    public Parser addTypeRemapping(String input, String newType, EnumSet newCasts) {
        assembled = false;

        String theInput = input.trim().toLowerCase(Locale.ENGLISH);
        String theType = newType.trim().toUpperCase(Locale.ENGLISH);

        Set mappingsForInput = typeRemappings.computeIfAbsent(theInput, k -> new HashSet<>());

        if (!mappingsForInput.contains(theType)) {
            mappingsForInput.add(theType);
            castsOfTargets.put(theType+':'+theInput, newCasts);
        }
        return this;
    }

    // --------------------------------------------

    public static String cleanupFieldValue(String fieldValue) {
        final int colonPos = fieldValue.indexOf(':');
        if (colonPos == -1) {
            return fieldValue.toLowerCase(Locale.ENGLISH);
        }

        final String fieldType = fieldValue.substring(0, colonPos);
        final String fieldName = fieldValue.substring(colonPos + 1);

        return fieldType.toUpperCase(Locale.ENGLISH)+':'+ fieldName.toLowerCase(Locale.ENGLISH);
    }

    // --------------------------------------------


    /**
     * Parse the value and return a new instance of RECORD.
     * For this method to work the RECORD class may NOT be an inner class.
     */
    public RECORD parse(final String value)
        throws DissectionFailure, InvalidDissectorException, MissingDissectorsException {
        assembleDissectors();
        final Parsable parsable = createParsable();
        if (parsable == null) {
            return null;
        }
        parsable.setRootDissection(rootType, value);
        return parse(parsable).getRecord();
    }

    // --------------------------------------------

    /**
     * Parse the value and call all configured setters in the provided instance of RECORD.
     */
    public RECORD parse(final RECORD record, final String value)
        throws DissectionFailure, InvalidDissectorException, MissingDissectorsException {
        assembleDissectors();
        final Parsable parsable = createParsable(record);
        parsable.setRootDissection(rootType, value);
        return parse(parsable).getRecord();
    }

    // --------------------------------------------

    Parsable parse(final Parsable parsable)
        throws DissectionFailure, InvalidDissectorException, MissingDissectorsException {
        assembleDissectors();

        if (!assembled) {
            return null;
        }

        // Values look like "TYPE:foo.bar"
        Set toBeParsed = new HashSet<>(parsable.getToBeParsed());

        while (!toBeParsed.isEmpty()) {
            for (ParsedField fieldThatNeedsToBeParsed : toBeParsed) {
                parsable.setAsParsed(fieldThatNeedsToBeParsed);
                Set dissectorSet = compiledDissectors.get(fieldThatNeedsToBeParsed.getId());
                if (dissectorSet != null) {
                    for (DissectorPhase dissector : dissectorSet) {
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Dissect {} with {}", fieldThatNeedsToBeParsed, dissector.instance.getClass().getName());
                        }
                        dissector.instance.dissect(parsable, fieldThatNeedsToBeParsed.getName());
                    }
                } else {
                    LOG.trace("NO DISSECTORS FOR \"{}\"", fieldThatNeedsToBeParsed);
                }
            }
            toBeParsed.clear();
            toBeParsed.addAll(parsable.getToBeParsed());
        }
        return parsable;
    }

    // --------------------------------------------

    void store(final RECORD record, final String key, final String name, final Value value) {
        boolean calledASetter = false;

        if (value == null) {
            LOG.error("Got a null value to store for key={}  name={}.", key, name);
            return; // Nothing to do
        }

        final Set> methodPairs = targets.get(key);
        if (methodPairs == null) {
            LOG.error("NO methods for key={}  name={}.", key, name);
            return;
        }

        EnumSet castsTo = castsOfTargets.get(key);
        if (castsTo == null) {
            castsTo = castsOfTargets.get(name);
            if (castsTo == null) {
                LOG.error("NO casts for \"{}\"", name);
                return;
            }
        }

        for (Pair methodPair : methodPairs) {
            Method method = methodPair.getLeft();
            if (method != null) {
                SetterPolicy setterPolicy = methodPair.getRight();
                try {
                    Class[] parameters = method.getParameterTypes();
                    Class valueClass = parameters[parameters.length - 1]; // Always the last one

                    if (valueClass == String.class) {
                        if (castsTo.contains(Casts.STRING)) {
                            String stringValue = value.getString();
                            if (stringValue == null) {
                                if (setterPolicy == NOT_NULL || setterPolicy == NOT_EMPTY) {
                                    calledASetter = true;
                                    continue;
                                }
                            } else {
                                if (stringValue.isEmpty() && setterPolicy == NOT_EMPTY) {
                                    calledASetter = true;
                                    continue;
                                }
                            }
                            if (parameters.length == 2) {
                                method.invoke(record, name, stringValue);
                            } else {
                                method.invoke(record, stringValue);
                            }
                            calledASetter = true;
                        }
                        continue;
                    }

                    if (valueClass == Long.class) {
                        if (castsTo.contains(Casts.LONG)) {
                            Long longValue = value.getLong();
                            if (longValue == null &&
                                (setterPolicy == NOT_NULL || setterPolicy == NOT_EMPTY)) {
                                calledASetter = true;
                                continue;
                            }
                            if (parameters.length == 2) {
                                method.invoke(record, name, longValue);
                            } else {
                                method.invoke(record, longValue);
                            }
                            calledASetter = true;
                        }
                        continue;
                    }

                    if (valueClass == Double.class) {
                        if (castsTo.contains(Casts.DOUBLE)) {
                            Double doubleValue = value.getDouble();
                            if (doubleValue == null &&
                                (setterPolicy == NOT_NULL || setterPolicy == NOT_EMPTY)) {
                                calledASetter = true;
                                continue;
                            }
                            if (parameters.length == 2) {
                                method.invoke(record, name, doubleValue);
                            } else {
                                method.invoke(record, doubleValue);
                            }
                            calledASetter = true;
                        }
                        continue;
                    }

                    throw new FatalErrorDuringCallOfSetterMethod(
                            "Tried to call setter with unsupported class :" +
                            " key = \"" + key + "\" " +
                            " name = \"" + name + "\" " +
                            " value = \"" + value + "\"" +
                            " castsTo = \"" + castsTo + "\"");

                } catch (final Exception e) {
                    throw new FatalErrorDuringCallOfSetterMethod(e.getMessage() + " caused by \"" +
                            e.getCause() + "\" when calling \"" +
                            method.toGenericString() + "\" for " +
                            " key = \"" + key + "\" " +
                            " name = \"" + name + "\" " +
                            " value = \"" + value + "\"" +
                            " castsTo = \"" + castsTo + "\"", e);
                }
            }
        }

        if (!calledASetter) {
            throw new FatalErrorDuringCallOfSetterMethod("No setter called for " +
                    " key = \"" + key + "\" " +
                    " name = \"" + name + "\" " +
                    " value = \"" + value + "\"");
        }
    }

    // --------------------------------------------

    private Parsable createParsable(RECORD record) {
        return new Parsable<>(this, record, typeRemappings);
    }

    public Parsable createParsable() {
        RECORD record;

        try {
            Constructor co = recordClass.getConstructor();
            record = co.newInstance();
        } catch (Exception e) {
            LOG.error("Unable to create instance: {}", e.getMessage());
            return null;
        }
        return createParsable(record);
    }

    // --------------------------------------------

    /**
     * This method is for use by the developer to query the parser about
     * the possible paths that may be extracted.
     * @return A sorted list of all possible paths that could be determined automatically.
     */
    public List getPossiblePaths() {
        return getPossiblePaths(15, true);
    }

    /**
     * This method is for use by the developer to query the parser about
     * the possible paths that may be extracted.
     * @param maxDepth The maximum recursion depth
     * @return A sorted list of all possible paths that could be determined automatically.
     */
    public List getPossiblePaths(int maxDepth) {
        return getPossiblePaths(maxDepth, true);
    }

    /**
     * This method is for use by the developer to query the parser about
     * the possible paths that may be extracted.
     * @param maxDepth The maximum recursion depth
     * @param sortList Must the list of paths be sorted?
     * @return A list of all possible paths that could be determined automatically.
     */
    public List getPossiblePaths(int maxDepth, boolean sortList) {
        if (allDissectors.isEmpty()) {
            return Collections.emptyList(); // nothing to do.
        }

        try {
            assembleDissectors();
        } catch (MissingDissectorsException | InvalidDissectorException e) {
            // Simply swallow this one
        }
        List paths = new ArrayList<>();

        Map> pathNodes = new HashMap<>();

        for (Dissector dissector : allDissectors) {
            final String inputType = dissector.getInputType();
            if (inputType == null) {
                LOG.error("Dissector returns null on getInputType(): [{}]", dissector.getClass().getCanonicalName());
                return Collections.emptyList();
            }

            final List outputs = dissector.getPossibleOutput();

            if (LOG.isDebugEnabled()) {
                LOG.debug("------------------------------------");
                LOG.debug("Possible: Dissector IN {}", inputType);
                for (String output: outputs) {
                    LOG.debug("Possible:          --> {}", output);
                }
            }

            List existingOutputs = pathNodes.get(inputType);
            if (existingOutputs != null) {
                outputs.addAll(existingOutputs);
            }
            pathNodes.put(inputType, outputs);
        }

        findAdditionalPossiblePaths(pathNodes, paths, "", rootType, maxDepth, "");

        for (Entry> typeRemappingSet: typeRemappings.entrySet()) {
            for (String typeRemapping: typeRemappingSet.getValue()) {

                String remappedPath = typeRemapping + ':' + typeRemappingSet.getKey();
                LOG.debug("Adding remapped path: {}", remappedPath);
                paths.add(remappedPath);
                findAdditionalPossiblePaths(pathNodes, paths, typeRemappingSet.getKey(), typeRemapping, maxDepth - 1, "");
            }
        }

        if (sortList) {
            // If so desired sort the list by the name of the field (i.e. NOT the name of the type)
            paths = paths
                .stream()
                .map(s -> s.split(":")).map(splits -> splits[1]+":"+splits[0]) // Swap type and field
                .sorted(String::compareTo)                                     // Sort by field
                .map(s -> s.split(":")).map(splits -> splits[1]+":"+splits[0]) // Swap type and field back to normal
                .collect(Collectors.toList());
        }

        return paths;
    }

    /**
     * Add all child paths in respect to the base (which is already present in the result set)
     */
    private void findAdditionalPossiblePaths(Map> pathNodes,
                                             List paths,
                                             String base,
                                             String baseType,
                                             int maxDepth,
                                             String logPrefix) {
        if (maxDepth == 0) {
            return;
        }

        LOG.debug("Possible:{} > {}:{}", logPrefix, baseType, base);

        if (pathNodes.containsKey(baseType)) {
            List childPaths = pathNodes.get(baseType);
            if (childPaths != null) {
                for (String childPath : childPaths) {
                    final int colonPos = childPath.indexOf(':');
                    final String childType = childPath.substring(0, colonPos);
                    final String childName = childPath.substring(colonPos + 1);

                    String childBase;
                    if (base.isEmpty()) {
                        childBase = childName;
                    } else {
                        if (childName.isEmpty()) {
                            childBase = base;
                        } else {
                            childBase = base + '.' + childName;
                        }
                    }

                    String newPath = childType + ':' + childBase;
                    if (!paths.contains(newPath)) {
                        LOG.debug("Possible:{} + {}:{}", logPrefix, childType, childBase);
                        paths.add(childType + ':' + childBase);

                        findAdditionalPossiblePaths(pathNodes, paths, childBase, childType, maxDepth - 1, logPrefix + "--");
                    }
                }
            }
        }
        LOG.debug("Possible:{} < {}:{}", logPrefix, baseType, base);
    }

    // --------------------------------------------

}


================================================
FILE: parser-core/src/main/java/nl/basjes/parse/core/SimpleDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static nl.basjes.parse.core.Casts.NO_CASTS;

public abstract class SimpleDissector extends Dissector {

    String inputType;
    // Using HashMap instead of Map<> because a Map<> is not Serializable
    private HashMap> outputTypes;

    private HashMap> outputCasts;

    public SimpleDissector(String inputType, Map> outputTypes) {
        this.inputType = inputType;
        this.outputTypes = new HashMap<>(outputTypes);

        outputCasts = new HashMap<>(outputTypes.size());
        for (Map.Entry> type: outputTypes.entrySet()) {
            outputCasts.put(type.getKey().split(":", 2)[1], type.getValue());
        }
    }

    @Override
    public String getInputType() {
        return inputType;
    }

    @Override
    public void setInputType(String nInputType) {
        inputType = nInputType;
    }

    @Override
    public List getPossibleOutput() {
        return new ArrayList<>(outputTypes.keySet().stream().sorted().toList());
    }

    @Override
    public EnumSet prepareForDissect(String inputname, String outputname) {
        String name = extractFieldName(inputname, outputname);
        return outputCasts.getOrDefault(name, NO_CASTS);
    }

    @Override
    protected void initializeNewInstance(Dissector newInstance) throws InvalidDissectorException {
        if (newInstance instanceof SimpleDissector) {
            SimpleDissector dissector = (SimpleDissector) newInstance;
            dissector.inputType     = inputType;
            dissector.outputTypes   = outputTypes;
            dissector.outputCasts   = outputCasts;
        }
    }

    @Override
    public final void dissect(Parsable parsable, String inputname) throws DissectionFailure {
        final ParsedField field = parsable.getParsableField(getInputType(), inputname);
        Value value = field.getValue();
        if (value == null) {
            return; // Nothing to do here
        }
        dissect(parsable, inputname, value);
    }

    public abstract void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure;

}


================================================
FILE: parser-core/src/main/java/nl/basjes/parse/core/Value.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nl.basjes.parse.core;

public class Value {

    enum Filled {
        STRING,
        LONG,
        DOUBLE
    }

    private final Filled filled;
    private String s = null;
    private Long l = null;
    private Double d = null;

    public Value(String p) {
        filled = Filled.STRING;
        this.s = p;
    }

    public Value(Long p) {
        filled = Filled.LONG;
        this.l = p;
    }

    public Value(Double p) {
        filled = Filled.DOUBLE;
        this.d = p;
    }

    public String getString() {
        switch (filled) {
            case LONG:
                return l == null ? null : Long.toString(l);
            case DOUBLE:
                return d == null ? null : Double.toString(d);
            default: // == case STRING:
                return s;
        }
    }

    public Long getLong() {
        switch (filled) {
            case STRING:
                try {
                    return s == null ? null : Long.parseLong(s);
                } catch (NumberFormatException e) {
                    return null;
                }
            case DOUBLE:
                return d == null ? null : (long) Math.floor(d + 0.5d); // Apply rounding
            default: // == case LONG:
                return l;
        }
    }

    public Double getDouble() {
        switch (filled) {
            case STRING:
                try {
                    return s == null ? null : Double.parseDouble(s);
                } catch (NumberFormatException e) {
                    return null;
                }
            case LONG:
                return l == null ? null : Double.valueOf(l);
            default: // == case DOUBLE:
                return d;
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb  .append("Value{")
            .append("filled=").append(filled);
        if (s == null) {
            sb.append(", s=null");
        } else {
            sb.append(", s='").append(s).append('\'');
        }
        sb
            .append(", l=").append(l)
            .append(", d=").append(d)
            .append('}');
        return sb.toString();
    }
}


================================================
FILE: parser-core/src/main/java/nl/basjes/parse/core/exceptions/DissectionFailure.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.exceptions;

public class DissectionFailure extends Exception {
    private static final long serialVersionUID = 1L;

    public DissectionFailure(String message) {
        super(message);
    }
    public DissectionFailure(String message, Throwable cause) {
        super(message, cause);
    }
}


================================================
FILE: parser-core/src/main/java/nl/basjes/parse/core/exceptions/FatalErrorDuringCallOfSetterMethod.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.exceptions;

public class FatalErrorDuringCallOfSetterMethod extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public FatalErrorDuringCallOfSetterMethod(String message){
        super("Error occurred during setter call: "+ message);
    }

    public FatalErrorDuringCallOfSetterMethod(String message, Throwable cause){
        super("Error occurred during setter call: "+ message, cause);
    }

}


================================================
FILE: parser-core/src/main/java/nl/basjes/parse/core/exceptions/InvalidDissectorException.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.exceptions;

public class InvalidDissectorException extends Exception {
    private static final long serialVersionUID = 1L;

    public InvalidDissectorException() {
        super("Something went very wrong in constructing the dissector.");
    }

    public InvalidDissectorException(String message) {
        super(message);
    }

    public InvalidDissectorException(String message, Throwable cause) {
        super(message, cause);
    }

}


================================================
FILE: parser-core/src/main/java/nl/basjes/parse/core/exceptions/InvalidFieldMethodSignature.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.exceptions;

import java.lang.reflect.Method;

public class InvalidFieldMethodSignature extends RuntimeException {
    private static final long serialVersionUID = 1L;

    public InvalidFieldMethodSignature(final Method method) {
        super("The method " + method.getDeclaringClass().getName() + "." + method.getName()
                + " does not conform to \"" + method.getName() + "(String name, String value)\".");
    }
}


================================================
FILE: parser-core/src/main/java/nl/basjes/parse/core/exceptions/MissingDissectorsException.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.exceptions;

public class MissingDissectorsException extends Exception {
    private static final long serialVersionUID = 1L;

    public MissingDissectorsException(String message) {
        super(message);
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserCastsTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static nl.basjes.parse.core.Casts.DOUBLE_ONLY;
import static nl.basjes.parse.core.Casts.LONG_ONLY;
import static nl.basjes.parse.core.Casts.NO_CASTS;
import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static nl.basjes.parse.core.Casts.STRING_OR_DOUBLE;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG_OR_DOUBLE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

class ParserCastsTest {

    public static class MyDissector extends Dissector {

        public MyDissector() {
            // Empty
        }

        @Override
        public void dissect(Parsable parsable, final String inputname) throws DissectionFailure {
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_null", (String)null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_good", "123");

            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_null", (String)null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_bad", "Something");
            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_good", "123");

            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_null", (String)null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_bad", "Something");
            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_good", "123");

            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_long_null", (String)null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_double_null", (String)null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "multi_null", (String)null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_long_good", "123");
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_double_good", "123");
            parsable.addDissection(inputname, "OUTPUT_TYPE", "multi_good", "123");

        }

        @Override
        public String getInputType() {
            return "INPUT_TYPE";
        }

        @Override
        public List getPossibleOutput() {
            List result = new ArrayList<>();
            result.add("OUTPUT_TYPE:string_null");
            result.add("OUTPUT_TYPE:string_good");
            result.add("OUTPUT_TYPE:long_null");
            result.add("OUTPUT_TYPE:long_bad");
            result.add("OUTPUT_TYPE:long_good");
            result.add("OUTPUT_TYPE:double_null");
            result.add("OUTPUT_TYPE:double_bad");
            result.add("OUTPUT_TYPE:double_good");
            result.add("OUTPUT_TYPE:string_long_null");
            result.add("OUTPUT_TYPE:string_double_null");
            result.add("OUTPUT_TYPE:multi_null");
            result.add("OUTPUT_TYPE:string_long_good");
            result.add("OUTPUT_TYPE:string_double_good");
            result.add("OUTPUT_TYPE:multi_good");
            return result;
        }


        private static final Map> PREPARE_FOR_DISSECT_MAP = new HashMap<>();
        static {
            PREPARE_FOR_DISSECT_MAP.put("string_null",          STRING_ONLY);
            PREPARE_FOR_DISSECT_MAP.put("string_good",          STRING_ONLY);

            PREPARE_FOR_DISSECT_MAP.put("long_null",            LONG_ONLY);
            PREPARE_FOR_DISSECT_MAP.put("long_bad",             LONG_ONLY);
            PREPARE_FOR_DISSECT_MAP.put("long_good",            LONG_ONLY);

            PREPARE_FOR_DISSECT_MAP.put("double_null",          DOUBLE_ONLY);
            PREPARE_FOR_DISSECT_MAP.put("double_bad",           DOUBLE_ONLY);
            PREPARE_FOR_DISSECT_MAP.put("double_good",          DOUBLE_ONLY);
            PREPARE_FOR_DISSECT_MAP.put("string_long_null",     STRING_OR_LONG);
            PREPARE_FOR_DISSECT_MAP.put("string_double_null",   STRING_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("multi_null",           STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("string_long_good",     STRING_OR_LONG);
            PREPARE_FOR_DISSECT_MAP.put("string_double_good",   STRING_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("multi_good",           STRING_OR_LONG_OR_DOUBLE);
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return PREPARE_FOR_DISSECT_MAP.getOrDefault(outputname, NO_CASTS);
        }
    }

    public static class MyParser extends Parser {
        public MyParser(final Class clazz) {
            super(clazz);
            addDissector(new MyDissector());
            setRootType("INPUT_TYPE");
        }
    }

    public static class MyRecord {
        private int count = 0;
        @Field({"OUTPUT_TYPE:string_null",
                "OUTPUT_TYPE:string_long_null",
                "OUTPUT_TYPE:string_double_null",
                "OUTPUT_TYPE:multi_null"})
        public void setStringNull(String value) {
            assertEquals(null, value);
            count++;
        }

        @Field({"OUTPUT_TYPE:string_good",
                "OUTPUT_TYPE:string_long_good",
                "OUTPUT_TYPE:string_double_good",
                "OUTPUT_TYPE:multi_good"})
        public void setStringGood(String value) {
            assertEquals("123", value);
            count++;
        }

        @Field({"OUTPUT_TYPE:long_null",
                "OUTPUT_TYPE:long_bad",
                "OUTPUT_TYPE:string_long_null",
                "OUTPUT_TYPE:multi_null"})
        public void setLongNull(Long value) {
            assertEquals(null, value);
            count++;
        }

        @Field({"OUTPUT_TYPE:long_good",
                "OUTPUT_TYPE:string_long_good",
                "OUTPUT_TYPE:multi_good"})
        public void setLongGood(Long value) {
            assertEquals(Long.valueOf(123L), value);
            count++;
        }

        @Field({"OUTPUT_TYPE:double_null",
                "OUTPUT_TYPE:double_bad",
                "OUTPUT_TYPE:string_double_null",
                "OUTPUT_TYPE:multi_null"})
        public void setDoubleNull(Double value) {
            assertEquals(null, value);
            count++;
        }

        @Field({"OUTPUT_TYPE:double_good",
                "OUTPUT_TYPE:string_double_good",
                "OUTPUT_TYPE:multi_good"})
        public void setDoubleGood(Double value) {
            assertEquals(123D, value, 0.0001D);
            count++;
        }

        @SuppressWarnings("UnusedParameters")
        @Field({"OUTPUT_TYPE:long_null",
                "OUTPUT_TYPE:long_bad",
                "OUTPUT_TYPE:long_good",
                "OUTPUT_TYPE:string_long_null",
                "OUTPUT_TYPE:string_long_good"})
        public void setLongWrongSignature(String name, Double value) {
            fail("This setter uses Double but that is not allowed for \""+name+"\" ");
        }

        @SuppressWarnings("UnusedParameters")
        @Field({"OUTPUT_TYPE:double_null",
                "OUTPUT_TYPE:double_bad",
                "OUTPUT_TYPE:double_good",
                "OUTPUT_TYPE:string_double_null",
                "OUTPUT_TYPE:string_double_good"})
        public void setDoubleWrongSignature(String name, Long value) {
            fail("This setter uses Long but that is not allowed for \""+name+"\" ");
        }
    }

    @Test
    void testValidCasting() throws Exception {
        Parser parser = new MyParser<>(MyRecord.class);
        MyRecord output = new MyRecord();
        parser.parse(output, "Something");
        assertEquals(22, output.count);

        Map> allCasts = parser.getAllCasts();
        assertEquals(STRING_ONLY,               allCasts.get("OUTPUT_TYPE:string_good"));
        assertEquals(LONG_ONLY,                 allCasts.get("OUTPUT_TYPE:long_good"));
        assertEquals(DOUBLE_ONLY,               allCasts.get("OUTPUT_TYPE:double_good"));
        assertEquals(STRING_OR_LONG,            allCasts.get("OUTPUT_TYPE:string_long_good"));
        assertEquals(STRING_OR_DOUBLE,          allCasts.get("OUTPUT_TYPE:string_double_good"));
        assertEquals(STRING_OR_LONG_OR_DOUBLE,  allCasts.get("OUTPUT_TYPE:multi_good"));

        assertEquals(STRING_ONLY,               parser.getCasts("OUTPUT_TYPE:string_good"));
        assertEquals(LONG_ONLY,                 parser.getCasts("OUTPUT_TYPE:long_good"));
        assertEquals(DOUBLE_ONLY,               parser.getCasts("OUTPUT_TYPE:double_good"));
        assertEquals(STRING_OR_LONG,            parser.getCasts("OUTPUT_TYPE:string_long_good"));
        assertEquals(STRING_OR_DOUBLE,          parser.getCasts("OUTPUT_TYPE:string_double_good"));
        assertEquals(STRING_OR_LONG_OR_DOUBLE,  parser.getCasts("OUTPUT_TYPE:multi_good"));
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserDissectionOutputTypesTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static nl.basjes.parse.core.Casts.NO_CASTS;
import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG_OR_DOUBLE;
import static org.junit.jupiter.api.Assertions.assertEquals;

class ParserDissectionOutputTypesTest {

    public static class TestDissector extends Dissector {

        public TestDissector() {
            // Empty
        }

        @Override
        public void dissect(Parsable parsable, final String inputname) throws DissectionFailure {
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_set_null", (String) null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string_set_string", "42");

            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_set_string_null", (String) null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_set_string", "42");

            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_set_longclass_null", (Long) null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_set_longclass", Long.valueOf(42));
            parsable.addDissection(inputname, "OUTPUT_TYPE", "long_set_longprimitive", 42L);

            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_string_null", (String) null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_string", "42");

            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_longclass_null", (Long) null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_longclass", Long.valueOf(42));
            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_longprimitive", 42L);

            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_doubleclass_null", (Double) null);
            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_doubleclass", Double.valueOf(42));
            parsable.addDissection(inputname, "OUTPUT_TYPE", "double_set_doubleprimitive", 42D);

        }

        @Override
        public String getInputType() {
            return "INPUT_TYPE";
        }

        @Override
        public List getPossibleOutput() {
            List result = new ArrayList<>();
            result.add("OUTPUT_TYPE:string_set_null");
            result.add("OUTPUT_TYPE:string_set_string");

            result.add("OUTPUT_TYPE:long_set_longclass_null");
            result.add("OUTPUT_TYPE:long_set_longclass");
            result.add("OUTPUT_TYPE:long_set_longprimitive");
            result.add("OUTPUT_TYPE:long_set_string_null");
            result.add("OUTPUT_TYPE:long_set_string");

            result.add("OUTPUT_TYPE:double_set_doubleclass_null");
            result.add("OUTPUT_TYPE:double_set_doubleclass");
            result.add("OUTPUT_TYPE:double_set_doubleprimitive");
            result.add("OUTPUT_TYPE:double_set_longclass_null");
            result.add("OUTPUT_TYPE:double_set_longclass");
            result.add("OUTPUT_TYPE:double_set_longprimitive");
            result.add("OUTPUT_TYPE:double_set_string_null");
            result.add("OUTPUT_TYPE:double_set_string");
            return result;
        }

        private static final Map> PREPARE_FOR_DISSECT_MAP = new HashMap<>();

        static {
            PREPARE_FOR_DISSECT_MAP.put("string_set_null",              STRING_ONLY);
            PREPARE_FOR_DISSECT_MAP.put("string_set_string",            STRING_ONLY);

            PREPARE_FOR_DISSECT_MAP.put("long_set_longclass_null",      STRING_OR_LONG);
            PREPARE_FOR_DISSECT_MAP.put("long_set_longclass",           STRING_OR_LONG);
            PREPARE_FOR_DISSECT_MAP.put("long_set_longprimitive",       STRING_OR_LONG);
            PREPARE_FOR_DISSECT_MAP.put("long_set_string_null",         STRING_OR_LONG);
            PREPARE_FOR_DISSECT_MAP.put("long_set_string",              STRING_OR_LONG);

            PREPARE_FOR_DISSECT_MAP.put("double_set_doubleclass_null",  STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("double_set_doubleclass",       STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("double_set_doubleprimitive",   STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("double_set_longclass_null",    STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("double_set_longclass",         STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("double_set_longprimitive",     STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("double_set_string_null",       STRING_OR_LONG_OR_DOUBLE);
            PREPARE_FOR_DISSECT_MAP.put("double_set_string",            STRING_OR_LONG_OR_DOUBLE);
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return PREPARE_FOR_DISSECT_MAP.getOrDefault(outputname, NO_CASTS);
        }
    }

    public static class TestParser extends Parser {
        TestParser(final Class clazz) {
            super(clazz);
            addDissector(new TestDissector());
            setRootType("INPUT_TYPE");
        }
    }

    @SuppressWarnings("unused")
    public static class TestRecord {
        private int count = 0;

        @Field({
            "OUTPUT_TYPE:string_set_null",
            "OUTPUT_TYPE:long_set_longclass_null",
            "OUTPUT_TYPE:long_set_string_null",
            "OUTPUT_TYPE:double_set_doubleclass_null",
            "OUTPUT_TYPE:double_set_longclass_null",
            "OUTPUT_TYPE:double_set_string_null"
        })
        public void setStringNull(String value) {
            count++;
            assertEquals(null, value);
        }

        @Field({
            "OUTPUT_TYPE:long_set_longclass_null",
            "OUTPUT_TYPE:long_set_string_null",
            "OUTPUT_TYPE:double_set_doubleclass_null",
            "OUTPUT_TYPE:double_set_longclass_null",
            "OUTPUT_TYPE:double_set_string_null"
        })
        public void setLongNull(Long value) {
            count++;
            assertEquals(null, value);
        }

        @Field({
            "OUTPUT_TYPE:double_set_doubleclass_null",
            "OUTPUT_TYPE:double_set_longclass_null",
            "OUTPUT_TYPE:double_set_string_null"
        })
        public void setDoubleNull(Double value) {
            count++;
            assertEquals(null, value);
        }

        @Field({
            "OUTPUT_TYPE:string_set_string",
            "OUTPUT_TYPE:long_set_longclass",
            "OUTPUT_TYPE:long_set_longprimitive",
            "OUTPUT_TYPE:long_set_string",
            "OUTPUT_TYPE:double_set_longclass",
            "OUTPUT_TYPE:double_set_longprimitive",
            "OUTPUT_TYPE:double_set_string"
        })
        public void setString(String value) {
            count++;
            assertEquals("42", value);
        }

        @Field({
            "OUTPUT_TYPE:double_set_doubleclass",
            "OUTPUT_TYPE:double_set_doubleprimitive"
        })
        public void setStringFromDouble(String value) {
            count++;
            assertEquals("42.0", value);
        }

        @Field({
            "OUTPUT_TYPE:long_set_longclass",
            "OUTPUT_TYPE:long_set_longprimitive",
            "OUTPUT_TYPE:long_set_string",
            "OUTPUT_TYPE:double_set_doubleclass",
            "OUTPUT_TYPE:double_set_doubleprimitive",
            "OUTPUT_TYPE:double_set_longclass",
            "OUTPUT_TYPE:double_set_longprimitive",
            "OUTPUT_TYPE:double_set_string"
        })
        public void setLong(Long value) {
            count++;
            assertEquals(Long.valueOf(42L), value);
        }

        @Field({
            "OUTPUT_TYPE:double_set_doubleclass",
            "OUTPUT_TYPE:double_set_doubleprimitive",
            "OUTPUT_TYPE:double_set_longclass",
            "OUTPUT_TYPE:double_set_longprimitive",
            "OUTPUT_TYPE:double_set_string"
        })
        public void setDouble(Double value) {
            count++;
            assertEquals(42D, value, 0.01);
        }
    }

    @Test
    void testSetterTypes() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);
        TestRecord output = new TestRecord();
        parser.parse(output, "Something");
        assertEquals(36, output.count);
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserDuplicateOutputTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.test.DissectorTester;
import org.junit.jupiter.api.Test;

import java.util.EnumSet;
import java.util.HashMap;

import static nl.basjes.parse.core.Casts.STRING_ONLY;

class ParserDuplicateOutputTest {

    public abstract static class MyDissector extends SimpleDissector {
        private static final HashMap> DISSECTOR_CONFIG = new HashMap<>();
        static {
            DISSECTOR_CONFIG.put("STRING:output",   STRING_ONLY);
        }

        public MyDissector() {
            super("INPUT", DISSECTOR_CONFIG);
        }
    }

    public static class FooDissector extends MyDissector {
        @Override
        public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
            parsable.addDissection(inputname, "STRING", "output", "foo");
        }
    }
    public static class BarDissector extends MyDissector {
        @Override
        public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
            parsable.addDissection(inputname, "STRING", "output", "bar");
        }
    }

    // Verify: If you have two dissectors doing the SAME input/output you should get BOTH
    @Test
    void testParseString() {
        DissectorTester.create()
            .verbose()
            .withDissector(new FooDissector())
            .withDissector(new BarDissector())
            .withInput("SomeThing")
            .printPossible()
            .expect("STRING:output", "foo")
            .expect("STRING:output", "bar")
            .checkExpectations();
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserExceptionsTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.InvalidFieldMethodSignature;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

class ParserExceptionsTest {

    public static class TestDissector extends Dissector {
        private String inputType;
        private String outputType;
        private String outputName;

        public TestDissector(String inputType, String outputType, String outputName) {
            init(inputType, outputType, outputName);
        }

        public final void init(String inputtype, String outputtype, String outputname) {
            this.inputType  = inputtype;
            this.outputType = outputtype;
            this.outputName = outputname;
        }

        protected void initializeNewInstance(Dissector newInstance) {
            ((TestDissector)newInstance).init(inputType, outputType, outputName);
        }

        @Override
        public void dissect(Parsable parsable, final String inputname) throws DissectionFailure {
            final ParsedField field = parsable.getParsableField(inputType, inputname);
            parsable.addDissection(inputname, outputType, outputName, field.getValue());
        }

        @Override
        public String getInputType() {
            return inputType;
        }

        @Override
        public List getPossibleOutput() {
            List result = new ArrayList<>();
            result.add(outputType + ":" + outputName);
            return result;
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }
    }

    public static class TestDissectorOne extends TestDissector {
        public TestDissectorOne() {
            super("INPUTTYPE", "SOMETYPE", "output1");
        }
    }

    public static class TestDissectorTwo extends TestDissector {
        public TestDissectorTwo() {
            super("INPUTTYPE", "OTHERTYPE", "output2");
        }
    }

    public static class TestDissectorThree extends TestDissector {
        public TestDissectorThree() {
            super("SOMETYPE", "FOO", "foo");
        }
    }

    public static class TestDissectorFour extends TestDissector {
        public TestDissectorFour() {
            super("SOMETYPE", "BAR", "bar");
        }
    }

    public static class TestParser extends Parser {
        public TestParser(final Class clazz) {
            super(clazz);
            addDissector(new TestDissectorOne());
            addDissector(new TestDissectorTwo());

            // Needlessly clumsy to test the addDissectors method too.
            List dissectors = new ArrayList<>();
            dissectors.add(new TestDissectorThree());
            dissectors.add(new TestDissectorFour());
            addDissectors(dissectors);
            setRootType("INPUTTYPE");
        }
    }

    @SuppressWarnings("unused")
    public static class TestRecord {
        private String output1 = "xxx";
        @Field("SOMETYPE:output1")
        public void setValue1(String value) {
            output1 = "SOMETYPE1:SOMETYPE:output1:" + value;
        }

        private String output2 = "yyy";
//        @Field("OTHERTYPE:output") --> Set via direct method
        public void setValue2(String name, String value) {
            output2 = "OTHERTYPE2:" + name + ":" + value;
        }

        private String output3a = "xxx";
        private String output3b = "yyy";

        @Field({ "SOMETYPE:output1", "OTHERTYPE:output2" })
        public void setValue3(String name, String value) {
            if (name.startsWith("SOMETYPE:")) {
                output3a = "SOMETYPE3:" + name + ":" + value;
            } else {
                output3b = "OTHERTYPE3:" + name + ":" + value;
            }
        }

        private String output4a = "X";
        private String output4b = "Y";

        @Field({ "SOMETYPE:output1", "OTHERTYPE:output2", "SOMETYPE:output1", "OTHERTYPE:output2" })
        public void setValue4(String name, String value) {
            if (name.startsWith("SOMETYPE:")) {
                output4a = output4a + "=SOMETYPE:" + name + ":" + value;
            } else {
                output4b = output4b + "=OTHERTYPE:" + name + ":" + value;
            }
        }

        private String output5a = "X";
        private String output5b = "Y";

        @Field({ "SOMETYPE:output1", "OTHERTYPE:output2", "SOMETYPE:*", "OTHERTYPE:*" })
        public void setValue5(String name, String value) {
            if (name.startsWith("SOMETYPE:")) {
                output5a = output5a + "=SOMETYPE:" + name + ":" + value;
            } else {
                output5b = output5b + "=OTHERTYPE:" + name + ":" + value;
            }
        }

        private String output6 = "Z";
        @Field({ "FOO:output1.foo"})
        public void setValue6(String name, String value) {
            output6 = output6 + "=FOO:" + name + ":" + value;
        }

        private String output7 = "Z";
        @Field({ "BAR:output1.bar"})
        public void setValue7(String name, String value) {
            output7 = output7 + "=BAR:" + name + ":" + value;
        }

        private String output8 = "Z";
        public void setValue8(String name, String value) {
            output8 = output8 + "=" + name + ":" + value;
        }

        @SuppressWarnings({"UnusedDeclaration", "EmptyMethod"})
        public void badSetter1() {
        }

        @SuppressWarnings({"UnusedDeclaration", "EmptyMethod"})
        public void badSetter2(String name, Float value) {
        }
    }

    @Test
    void testParseString() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);

        String[] params = {"OTHERTYPE:output2"};
        parser.addParseTarget(TestRecord.class.getMethod("setValue2", String.class, String.class), Arrays.asList(params));

        TestRecord output = new TestRecord();
        parser.parse(output, "Something");
        assertEquals("SOMETYPE1:SOMETYPE:output1:Something", output.output1);
        assertEquals("OTHERTYPE2:OTHERTYPE:output2:Something", output.output2);
        assertEquals("SOMETYPE3:SOMETYPE:output1:Something", output.output3a);
        assertEquals("OTHERTYPE3:OTHERTYPE:output2:Something", output.output3b);
        assertEquals("X=SOMETYPE:SOMETYPE:output1:Something", output.output4a);
        assertEquals("Y=OTHERTYPE:OTHERTYPE:output2:Something", output.output4b);
        assertEquals("X=SOMETYPE:SOMETYPE:output1:Something=SOMETYPE:SOMETYPE:output1:Something", output.output5a);
        assertEquals("Y=OTHERTYPE:OTHERTYPE:output2:Something=OTHERTYPE:OTHERTYPE:output2:Something", output.output5b);
        assertEquals("Z=FOO:FOO:output1.foo:Something", output.output6);
        assertEquals("Z=BAR:BAR:output1.bar:Something", output.output7);
    }

    @Test
    void testGetPossiblePaths() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);

        String[] params = {"OTHERTYPE:output2"};
        parser.addParseTarget(TestRecord.class.getMethod("setValue2", String.class, String.class), Arrays.asList(params));

        List paths = parser.getPossiblePaths(3);
        assertEquals(4, paths.size());
        assertTrue(paths.contains("SOMETYPE:output1"));
        assertTrue(paths.contains("FOO:output1.foo"));
        assertTrue(paths.contains("BAR:output1.bar"));
        assertTrue(paths.contains("OTHERTYPE:output2"));
    }

    @Test
    void testBadSetter1() {
        Parser parser = new TestParser<>(TestRecord.class);

        String[] params = {"OTHERTYPE:output2"};
        assertThrows(InvalidFieldMethodSignature.class, () -> {
            parser.addParseTarget(TestRecord.class.getMethod("badSetter1"), Arrays.asList(params));
        });
    }

    @Test
    void testBadSetter2() {
        Parser parser = new TestParser<>(TestRecord.class);

        String[] params = {"OTHERTYPE:output2"};
        assertThrows(InvalidFieldMethodSignature.class, ()-> {
            parser.addParseTarget(TestRecord.class.getMethod("badSetter2", String.class, Float.class), Arrays.asList(params));
        });
    }

    public static class BrokenTestDissector extends Dissector {

        public BrokenTestDissector() {
        }

        @Override
        public boolean initializeFromSettingsParameter(String settings) {
            return true; // Everything went right
        }

        @Override
        public void dissect(Parsable parsable, String inputname) {
        }

        @Override
        public String getInputType() {
            return "FOO";
        }

        @Override
        public List getPossibleOutput() {
            List result = new ArrayList<>();
            result.add("FOO:bar");
            return result;
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }

        @Override
        public void prepareForRun() throws InvalidDissectorException {
            throw new InvalidDissectorException();
        }
    }

    @Test
    void testBrokenDissector() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);
        Dissector dissector = new BrokenTestDissector();
        parser.setRootType(dissector.getInputType());
        parser.addParseTarget(TestRecord.class.getMethod("setValue8", String.class, String.class), "FOO:bar");
        parser.addDissector(dissector);
        assertThrows(InvalidDissectorException.class, ()-> {
            parser.parse("Something");
        });
    }

    public static class BrokenTestDissector2 extends BrokenTestDissector {
        // Non public constructor
        BrokenTestDissector2() {
        }
    }

    @Test
    void testBrokenDissector2() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);
        Dissector dissector = new BrokenTestDissector2();
        parser.setRootType(dissector.getInputType());
        parser.addParseTarget(TestRecord.class.getMethod("setValue8", String.class, String.class), "FOO:bar");
        parser.addDissector(dissector);
        assertThrows(InvalidDissectorException.class, ()-> {
            parser.parse("Something");
        });
    }

    @Test
    void testChangeAfterStart() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);
        parser.parse("Something");
        assertNotNull(parser.addDissector(new BrokenTestDissector()));
    }

    @Test
    void testDropDissector1() {
        Parser parser = new TestParser<>(TestRecord.class);

        parser.dropDissector(TestDissectorOne.class);
        assertThrows(MissingDissectorsException.class, () -> {
            parser.parse("Something");
        });
    }

    @Test
    void testDropDissector2() {
        Parser parser = new TestParser<>(TestRecord.class);

        parser.dropDissector(TestDissectorOne.class);
        parser.addDissector(new TestDissectorOne());
        assertNotNull(parser.getPossiblePaths());
    }

    @Test
    void testDropDissector3() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);

        parser.parse("Something");
        assertNotNull(parser.dropDissector(TestDissectorOne.class));
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserInfiniteLoopTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertNotNull;

class ParserInfiniteLoopTest {

    public static class TestDissector extends Dissector {

        public TestDissector() {
            // Empty
        }

        @Override
        public void dissect(Parsable parsable, final String inputname) throws DissectionFailure {
            parsable.addDissection(inputname, "OUTPUT_TYPE", "string", "123");
        }

        @Override
        public String getInputType() {
            return "INPUT_TYPE";
        }

        @Override
        public List getPossibleOutput() {
            List result = new ArrayList<>();
            result.add("OUTPUT_TYPE:string");
            return result;
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return Casts.STRING_ONLY;
        }
    }

    public static class TestParser extends Parser {
        public TestParser(final Class clazz) {
            super(clazz);
            addDissector(new TestDissector());
            setRootType("INPUT_TYPE");
        }
    }

    public static class TestRecord {
        @SuppressWarnings({"EmptyMethod", "UnusedParameters"})
        @Field({"OUTPUT_TYPE:string"})
        public void set(String name, String value) {
            // Do nothing
        }
    }


    /**
     * This creates a dissector and a type remap that causes it to (effectively)
     * be an infinite recursive loop. This is the reproduction situation for a problem
     * that is now fixed.
     * @throws Exception in case of error
     */
    @Test
    void testInfiniteRecursionAvoidance() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);
        parser.addTypeRemapping("string", "INPUT_TYPE");
        TestRecord output = new TestRecord();
        assertNotNull(parser.parse(output, "Something"));
        // If this works then it will cleanly end (instead of a stack overflow)
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserNormalTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.test.NormalValuesDissector;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

class ParserNormalTest {

    public static class MyDissector extends Dissector {
        private String      inputType;
        private String      outputType;
        private String      outputName;
        private final Set outputNames = new HashSet<>();

        public MyDissector(String inputType, String outputType, String outputName) {
            this.inputType = inputType;
            this.outputType = outputType;
            this.outputName = outputName;
            this.outputNames.add(outputName);
        }

        public void init(String inputtype, String outputtype, String outputname) {
            this.inputType = inputtype;
            this.outputType = outputtype;
            this.outputName = outputname;
            this.outputNames.add(outputname);
        }

        @Override
        protected void initializeNewInstance(Dissector newInstance) {
            ((MyDissector)newInstance).init(inputType, outputType, outputName);
        }

        @Override
        public void dissect(Parsable parsable, String inputname) throws DissectionFailure {
            final ParsedField field = parsable.getParsableField(inputType, inputname);
            for (String outputname : outputNames) {
                parsable.addDissection(inputname, outputType, outputname, field.getValue());
            }
        }

        @Override
        public String getInputType() {
            return inputType;
        }

        @Override
        public List getPossibleOutput() {
            List result = new ArrayList<>();
            result.add(outputType + ":" + outputName);
            return result;
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            String name = outputname;
            String prefix = inputname + '.';
            if (outputname.startsWith(prefix)) {
                name = outputname.substring(prefix.length());
            }
            outputNames.add(name);
            return STRING_ONLY;
        }
    }

    public static class MyDissectorOne extends MyDissector {
        public MyDissectorOne() {
            super("INPUTTYPE", "SOMETYPE", "output1");
        }
    }

    public static class MyDissectorTwo extends MyDissector {
        public MyDissectorTwo() {
            super("INPUTTYPE", "OTHERTYPE", "output2");
        }
    }

    public static class MyDissectorThree extends MyDissector {
        public MyDissectorThree() {
            super("SOMETYPE", "FOO", "foo");
        }
    }

    public static class MyDissectorFour extends MyDissector {
        public MyDissectorFour() {
            super("SOMETYPE", "BAR", "bar");
        }
    }

    public static class MyDissectorWildCard extends MyDissector {
        public MyDissectorWildCard() {
            super("SOMETYPE", "WILD", "*");
        }

    }

    public static class TestParser extends Parser {
        public TestParser(final Class clazz) {
            super(clazz);
            addDissector(new MyDissectorOne());
            addDissector(new MyDissectorTwo());
            addDissector(new MyDissectorThree());
            addDissector(new MyDissectorFour());
            addDissector(new MyDissectorWildCard());
            setRootType("INPUTTYPE");
        }
    }

    @Test
    void testParseString() throws Exception {
        Parser parser = new TestParser<>(ParserNormalTestRecord.class);

        String[] params = {"OTHERTYPE:output2"};
        parser
            .addParseTarget(ParserNormalTestRecord.class.getMethod("setValue2", String.class, String.class), Arrays.asList(params))
            .dropDissector(MyDissectorWildCard.class)
            .addDissector(new MyDissectorWildCard());

        ParserNormalTestRecord output = new ParserNormalTestRecord();
        parser.parse(output, "Something");
        assertEquals("SOMETYPE1:SOMETYPE:output1:Something", output.getOutput1());
        assertEquals("OTHERTYPE2:OTHERTYPE:output2:Something", output.getOutput2());
        assertEquals("SOMETYPE3:SOMETYPE:output1:Something", output.getOutput3a());
        assertEquals("OTHERTYPE3:OTHERTYPE:output2:Something", output.getOutput3b());
        assertEquals("X=SOMETYPE:SOMETYPE:output1:Something", output.getOutput4a());
        assertEquals("Y=OTHERTYPE:OTHERTYPE:output2:Something", output.getOutput4b());
        assertEquals("X=SOMETYPE:SOMETYPE:output1:Something=SOMETYPE:SOMETYPE:output1:Something", output.getOutput5a());
        assertEquals("Y=OTHERTYPE:OTHERTYPE:output2:Something=OTHERTYPE:OTHERTYPE:output2:Something", output.getOutput5b());
        assertEquals("Z=FOO:FOO:output1.foo:Something", output.getOutput6());
        assertEquals("Z=BAR:BAR:output1.bar:Something", output.getOutput7());
        assertEquals("Z=WILD:WILD:output1.wild:Something", output.getOutput8());
    }

    // ---------------------------------------------
    @Test
    void testParseStringInstantiate() throws Exception {
        Parser parser = new TestParser<>(ParserNormalTestRecord.class);

        String[] params = {"OTHERTYPE:output2"};
        parser.addParseTarget(ParserNormalTestRecord.class.getMethod("setValue2", String.class, String.class), Arrays.asList(params));

        ParserNormalTestRecord output = parser.parse("Something");

        assertEquals("SOMETYPE1:SOMETYPE:output1:Something", output.getOutput1());
        assertEquals("OTHERTYPE2:OTHERTYPE:output2:Something", output.getOutput2());
        assertEquals("SOMETYPE3:SOMETYPE:output1:Something", output.getOutput3a());
        assertEquals("OTHERTYPE3:OTHERTYPE:output2:Something", output.getOutput3b());
        assertEquals("X=SOMETYPE:SOMETYPE:output1:Something", output.getOutput4a());
        assertEquals("Y=OTHERTYPE:OTHERTYPE:output2:Something", output.getOutput4b());
        assertEquals("X=SOMETYPE:SOMETYPE:output1:Something=SOMETYPE:SOMETYPE:output1:Something", output.getOutput5a());
        assertEquals("Y=OTHERTYPE:OTHERTYPE:output2:Something=OTHERTYPE:OTHERTYPE:output2:Something", output.getOutput5b());
        assertEquals("Z=FOO:FOO:output1.foo:Something", output.getOutput6());
        assertEquals("Z=BAR:BAR:output1.bar:Something", output.getOutput7());
        assertEquals("Z=WILD:WILD:output1.wild:Something", output.getOutput8());
    }

    // ---------------------------------------------

    @Test
    void testMissingDissector() {
        Parser parser = new TestParser<>(ParserNormalTestRecord.class);

        // Cripple the parser
        parser.dropDissector(MyDissectorTwo.class);

        ParserNormalTestRecord output = new ParserNormalTestRecord();

        assertThrows(MissingDissectorsException.class, () -> {
            parser.parse(output, "Something"); // Should fail.
        });
    }

    @Test
    void testGetPossiblePaths() throws Exception {
        Parser parser = new TestParser<>(ParserNormalTestRecord.class);

        String[] params = {"OTHERTYPE:output2"};
        parser.addParseTarget(ParserNormalTestRecord.class.getMethod("setValue2", String.class, String.class), Arrays.asList(params));

        List paths = parser.getPossiblePaths(3);
        for (String path : paths) {
            System.out.println("XXX " + path);
        }

    }

    @Test
    void testAddTypeRemapping() throws NoSuchMethodException, InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecord.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .addTypeRemapping("string", "STRINGXX")
            .addParseTarget("setStringValue", "STRINGXX:string")
            .addTypeRemapping("string", "STRINGYY")
            .addParseTarget("setStringValue", "STRINGYY:string")
            .parse("Doesn't matter")
            .expectString("STRINGXX:string", "FortyTwo")
            .expectString("STRINGYY:string", "FortyTwo");
    }

    @Test
    void testAddTypeRemappings() throws NoSuchMethodException, InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecord.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .addTypeRemapping("string", "STRINGXX")
            .addParseTarget("setStringValue", "STRINGXX:string")
            .addTypeRemappings(Collections.singletonMap("string", Collections.singleton("STRINGYY")))
            .addParseTarget("setStringValue", "STRINGYY:string")
            .parse("Doesn't matter")
            .expectString("STRINGXX:string", "FortyTwo")
            .expectString("STRINGYY:string", "FortyTwo");
    }

    @Test
    void testSetTypeRemapping() throws NoSuchMethodException, InvalidDissectorException, DissectionFailure {
        try{
            new Parser<>(TestRecord.class)
                .setRootType("INPUT")
                .addDissector(new NormalValuesDissector())
                .addTypeRemapping("string", "STRINGXX")
                .addParseTarget("setStringValue", "STRINGXX:string")
                // Should wipe previous
                .setTypeRemappings(Collections.singletonMap("string", Collections.singleton("STRINGYY")))
                .addParseTarget("setStringValue", "STRINGYY:string")
                .parse("Doesn't matter");

            fail("We should get an exception because the mapping to STRINGXX:string wass removed.");
        } catch (MissingDissectorsException mde) {
            assertTrue(mde.getMessage().contains("STRINGXX:string"));
        }
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserNormalTestRecord.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

public class ParserNormalTestRecord {

    public ParserNormalTestRecord() {
        // Empty but needed for instantiating
    }

    private String output1 = "xxx";

    @Field("SOMETYPE:output1")
    public void setValue1(String value) {
        output1 = "SOMETYPE1:SOMETYPE:output1:" + value;
    }

    public String getOutput1() {
        return output1;
    }

    private String output2 = "yyy";

    // @Field("OTHERTYPE:output") --> Set via direct method
    public void setValue2(String name, String value) {
        output2 = "OTHERTYPE2:" + name + ":" + value;
    }

    public String getOutput2() {
        return output2;
    }

    private String output3a = "xxx";
    private String output3b = "yyy";

    @Field({ "SOMETYPE:output1", "OTHERTYPE:output2" })
    public void setValue3(String name, String value) {
        if (name.startsWith("SOMETYPE:")) {
            output3a = "SOMETYPE3:" + name + ":" + value;
        } else {
            output3b = "OTHERTYPE3:" + name + ":" + value;
        }
    }

    public String getOutput3a() {
        return output3a;
    }

    public String getOutput3b() {
        return output3b;
    }

    private String output4a = "X";
    private String output4b = "Y";

    @Field({ "SOMETYPE:output1", "OTHERTYPE:output2", "SOMETYPE:output1", "OTHERTYPE:output2" })
    public void setValue4(String name, String value) {
        if (name.startsWith("SOMETYPE:")) {
            output4a = output4a + "=SOMETYPE:" + name + ":" + value;
        } else {
            output4b = output4b + "=OTHERTYPE:" + name + ":" + value;
        }
    }

    public String getOutput4a() {
        return output4a;
    }

    public String getOutput4b() {
        return output4b;
    }

    private String output5a = "X";
    private String output5b = "Y";

    @Field({ "SOMETYPE:output1", "OTHERTYPE:output2", "SOMETYPE:*", "OTHERTYPE:*" })
    public void setValue5(String name, String value) {
        if (name.startsWith("SOMETYPE:")) {
            output5a = output5a + "=SOMETYPE:" + name + ":" + value;
        } else {
            output5b = output5b + "=OTHERTYPE:" + name + ":" + value;
        }
    }

    public String getOutput5a() {
        return output5a;
    }

    public String getOutput5b() {
        return output5b;
    }

    private String output6 = "Z";

    @Field({ "FOO:output1.foo" })
    public void setValue6(String name, String value) {
        output6 = output6 + "=FOO:" + name + ":" + value;
    }

    public String getOutput6() {
        return output6;
    }

    private String output7 = "Z";

    @Field({ "BAR:output1.bar" })
    public void setValue7(String name, String value) {
        output7 = output7 + "=BAR:" + name + ":" + value;
    }

    public String getOutput7() {
        return output7;
    }

    private String output8 = "Z";

    @Field({ "WILD:output1.wild" })
    public void setValue8(String name, String value) {
        output8 = output8 + "=WILD:" + name + ":" + value;
    }

    public String getOutput8() {
        return output8;
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserResetTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.test.NormalValuesDissector;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static org.junit.jupiter.api.Assertions.assertEquals;

class ParserResetTest {

    public static class WildCardDissector extends SimpleDissector {

        // Deliberate Dissector bug: We use a List instead of a Set so any duplicates are retained.
        protected final List outputNames = new ArrayList<>();

        private static final Map> OUTPUT_TYPES = new HashMap<>();
        static {
            OUTPUT_TYPES.put("EXTRA:*", STRING_ONLY);
        }
        public WildCardDissector() {
            super("STRING", OUTPUT_TYPES);
        }

        @Override
        public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
            for (String outputName : outputNames) {
                parsable.addDissection(inputname, "EXTRA", outputName, outputName);
            }
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            String name = outputname;
            String prefix = inputname + '.';
            if (outputname.startsWith(prefix)) {
                name = outputname.substring(prefix.length());
            }
            outputNames.add(name);
            return STRING_ONLY;
        }
    }

    public static class DuplicateTestRecord {
        private final Map>  stringMap   = new HashMap<>(32);

        public void setStringValue(final String name, final String value) {
            stringMap.computeIfAbsent(name, s -> new ArrayList<>()).add(value);
        }
        public List getStringValues(final String name) {
            return stringMap.get(name);
        }
    }


    @Test
    void testParserReset() throws NoSuchMethodException, InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        Parser parser = new Parser<>(DuplicateTestRecord.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .addDissector(new WildCardDissector())
            .addParseTarget("setStringValue", "STRING:string")
            .addParseTarget("setStringValue", "EXTRA:string.one")
            .addParseTarget("setStringValue", "EXTRA:string.two");

        // This causes the parser to initialize
        parser.getPossiblePaths();

        // This should reset the parser completely
        parser.addDissector(null);

        DuplicateTestRecord testRecord = new DuplicateTestRecord();
        parser.parse(testRecord, "Doesn't matter");

        assertEquals("FortyTwo", testRecord.getStringValues("STRING:string").get(0));
        assertEquals("one",      testRecord.getStringValues("EXTRA:string.one").get(0));
        assertEquals("two",      testRecord.getStringValues("EXTRA:string.two").get(0));

        // There used to be a bug that would make some values arrive twice.
        assertEquals(1,          testRecord.getStringValues("STRING:string").size());
        assertEquals(1,          testRecord.getStringValues("EXTRA:string.one").size());
        assertEquals(1,          testRecord.getStringValues("EXTRA:string.two").size());
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserTypeColissionTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class ParserTypeColissionTest {

    public static class TestDissector extends Dissector {
        private String inputType;
        private String outputType;
        private String outputName;
        private String salt; // Each value that comes in is appended with this "salt"

        public TestDissector(String inputType, String outputType, String outputName, String salt) {
            this.inputType = inputType;
            this.outputType = outputType;
            this.outputName = outputName;
            this.salt = salt;
        }

        public void init(String inputtype, String outputtype, String outputname, String saltt) {
            this.inputType = inputtype;
            this.outputType = outputtype;
            this.outputName = outputname;
            this.salt = saltt;
        }

        @Override
        protected void initializeNewInstance(Dissector newInstance) {
            ((TestDissector)newInstance).init(inputType, outputType, outputName, salt);
        }

        @Override
        public void dissect(Parsable parsable, String inputname)
            throws DissectionFailure {
            final ParsedField field = parsable.getParsableField(inputType, inputname);
            parsable.addDissection(inputname, outputType, outputName, field.getValue().getString() + salt);
        }

        @Override
        public String getInputType() {
            return inputType;
        }

        @Override
        public List getPossibleOutput() {
            List result = new ArrayList<>();
            result.add(outputType + ":" + outputName);
            return result;
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }
    }

    public static class TestDissectorOne extends TestDissector {
        public TestDissectorOne() {
            super("INPUTTYPE", "SOMETYPE", "output", "+1");
        }
    }

    public static class TestDissectorTwo extends TestDissector {
        public TestDissectorTwo() {
            super("INPUTTYPE", "OTHERTYPE", "output", "+2");
        }
    }

    public static class TestDissectorSubOne extends TestDissector {
        public TestDissectorSubOne() {
            super("SOMETYPE", "SOMESUBTYPE", "output", "+S1");
        }
    }

    public static class TestDissectorSubTwo extends TestDissector {
        public TestDissectorSubTwo() {
            super("OTHERTYPE", "OTHERSUBTYPE", "output", "+S2");
        }
    }

    public static class TestDissectorSubSubOne extends TestDissector {
        public TestDissectorSubSubOne() {
            super("SOMESUBTYPE", "SOMESUBSUBTYPE", "output", "+SS1");
        }
    }

    public static class TestDissectorSubSubTwo extends TestDissector {
        public TestDissectorSubSubTwo() {
            super("OTHERSUBTYPE", "OTHERSUBSUBTYPE", "output", "+SS2");
        }
    }

    public static class TestParser extends Parser {
        public TestParser(final Class clazz) {
            super(clazz);
            addDissector(new TestDissectorOne());
            addDissector(new TestDissectorTwo());
            addDissector(new TestDissectorSubOne());
            addDissector(new TestDissectorSubTwo());
            addDissector(new TestDissectorSubSubOne());
            addDissector(new TestDissectorSubSubTwo());
            setRootType("INPUTTYPE");
        }
    }

    public static class TestRecord {
        private String output1 = "xxx";

        @Field("SOMETYPE:output")
        public void setValue1(String name, String value) {
            output1 = name + ":" + value;
        }

        private String output2 = "xxx";

        @Field("OTHERTYPE:output")
        public void setValue2(String name, String value) {
            output2 = name + ":" + value;
        }

        private String output3 = "xxx";

        @Field("SOMESUBSUBTYPE:output.output.output")
        public void setValue3(String name, String value) {
            output3 = name + ":" + value;
        }

        private String output4 = "xxx";

        @Field("OTHERSUBSUBTYPE:output.output.output")
        public void setValue4(String name, String value) {
            output4 = name + ":" + value;
        }

    }

    @Test
    void testParseString() throws Exception {
        Parser parser = new TestParser<>(TestRecord.class);

        TestRecord output = new TestRecord();
        parser.parse(output, "Something");
        assertEquals("SOMETYPE:output:Something+1", output.output1);
        assertEquals("OTHERTYPE:output:Something+2", output.output2);
        assertEquals("SOMESUBSUBTYPE:output.output.output:Something+1+S1+SS1", output.output3);
        assertEquals("OTHERSUBSUBTYPE:output.output.output:Something+2+S2+SS2", output.output4);
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/ParserTypeRemappingEdgeCase.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.junit.jupiter.api.Test;

import java.util.EnumSet;
import java.util.Map;
import java.util.TreeMap;

import static nl.basjes.parse.core.Casts.LONG_ONLY;
import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class ParserTypeRemappingEdgeCase {

    public static class TestDissectorLongAsString extends SimpleDissector {

        private static final Map> OUTPUT = new TreeMap<>();
        static {
            OUTPUT.put("LONG_AS_STRING:long_as_string", STRING_ONLY);
        }

        public TestDissectorLongAsString() {
            super("INPUTTYPE", OUTPUT);
        }

        @Override
        public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
            // This happens for example if you extract a query string parameter you know to be a number
            parsable.addDissection(inputname, "LONG_AS_STRING", "long_as_string", "42");
        }
    }

    public static class TestParser extends Parser {
        public TestParser(final Class clazz) {
            super(clazz);
            addDissector(new TestDissectorLongAsString());
            setRootType("INPUTTYPE");
        }
    }

    public static class Record {
        String stringName1 = "empty";
        String stringValue1 = "empty";
        public void set1(String name, String value){
            stringName1 = name;
            stringValue1 = value;
        }

        String stringName2 = "empty";
        String stringValue2 = "empty";
        public void set2(String name, String value){
            stringName2 = name;
            stringValue2 = value;
        }

        String longName = "empty";
        long longValue = 0;
        public void set(String name, Long value){
            longName = name;
            longValue = value;
        }
    }

    @Test
    void testParseString() throws Exception {
        Parser parser = new TestParser<>(Record.class);
        parser
            .addParseTarget(Record.class.getMethod("set1", String.class, String.class), "LONG_AS_STRING:long_as_string")

            // If we add a type remapping with a cast that does not include STRING it should still work.
            .addTypeRemapping("long_as_string", "SOMETHING", LONG_ONLY)
            .addParseTarget(Record.class.getMethod("set", String.class, Long.class), "SOMETHING:long_as_string")
            // And this one should NOT be called
            .addParseTarget(Record.class.getMethod("set2", String.class, String.class), "SOMETHING:long_as_string");

        Record output = new Record();
        parser.parse(output, "An input that does not matter");
        assertEquals("42", output.stringValue1);
        assertEquals("empty", output.stringValue2);
        assertEquals(42, output.longValue);
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/TestBadAPIUsage.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core;

import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.reference.BarDissector;
import nl.basjes.parse.core.reference.FooDissector;
import nl.basjes.parse.core.test.DissectorTester;
import nl.basjes.parse.core.test.NormalValuesDissector;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

public class TestBadAPIUsage {

    @Test
    void testChangingInputTypeShouldNotBePossibleByDefault() {
        assertThrows(InvalidDissectorException.class, () -> {
            new DissectorTester.DummyDissector().setInputType("Change should not be allowed");
        });
    }

    @Test
    void testDissectorString(){
        assertEquals(
            "{ BarDissector : BARINPUT --> " +
                "[ANY:barany, DOUBLE:bardouble, FLOAT:barfloat, INT:barint, LONG:barlong, STRING:barstring] }",
            new BarDissector().toString());
    }

    public static class NullInputDissector extends Dissector {
        @Override
        public void dissect(Parsable parsable, String inputname) {
        }
        @Override
        public String getInputType() {
            return null;
        }
        @Override
        public List getPossibleOutput() {
            return Collections.singletonList("FOO:foo");
        }
        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }
    }

    @Test
    void testNullInputHandling() {
        assertThrows(InvalidDissectorException.class, () -> {
            new Parser<>(Object.class).addDissector(new NullInputDissector()).parse("Foo");
        });
    }

    public static class NullOutputDissector extends Dissector {
        @Override
        public void dissect(Parsable parsable, String inputname) {
        }
        @Override
        public String getInputType() {
            return "SOMETHING";
        }
        @Override
        public List getPossibleOutput() {
            return Collections.emptyList();
        }
        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }
    }

    @Test
    void testNullOutputHandling() {
        assertThrows(InvalidDissectorException.class, () -> {
            new Parser<>(Object.class).addDissector(new NullOutputDissector()).parse("Foo");
        });
    }

    public static class EmptyOutputDissector extends Dissector {
        @Override
        public void dissect(Parsable parsable, String inputname) {
        }
        @Override
        public String getInputType() {
            return "SOMETHING";
        }
        @Override
        public List getPossibleOutput() {
            return Collections.emptyList();
        }
        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }
    }

    @Test
    void testEmptyOutputHandling() {
        assertThrows(InvalidDissectorException.class, () -> {
            new Parser<>(Object.class).addDissector(new EmptyOutputDissector()).parse("Foo");
        });
    }

    @Test
    void testFailZeroDissectors() {
        assertThrows(MissingDissectorsException.class, () -> {
            new Parser<>(TestRecord.class)
                .setRootType("INPUT")
                .failOnMissingDissectors()
                .addParseTarget("setStringValue", "SOMETHING:that.is.not.present")
                .addParseTarget("setStringValue", "STRING:string")
                .parse("Doesn't matter");
        });
    }

    @Test
    void testFailOnMissingDissectors() {
        assertThrows(MissingDissectorsException.class, () -> {
            new Parser<>(TestRecord.class)
                .setRootType("INPUT")
                .addDissector(new NormalValuesDissector())
                .addDissector(new FooDissector())
                .addDissector(new BarDissector())
                .failOnMissingDissectors()
                .addParseTarget("setStringValue", "SOMETHING:that.is.not.present")
                .addParseTarget("setStringValue", "STRING:string")
                .parse("Doesn't matter");
        });
    }

    @Test
    void testIgnoreMissingDissectors() throws NoSuchMethodException, InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecord.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .addDissector(new FooDissector())
            .addDissector(new BarDissector())
            .ignoreMissingDissectors()
            .addParseTarget("setStringValue", Parser.SetterPolicy.ALWAYS, "SOMETHING:that.is.not.present")
            .addParseTarget("setStringValue", Parser.SetterPolicy.ALWAYS, "STRING:string")
            .parse("Doesn't matter");
    }

    @Test
    void testNoSuchSetter() {
        assertThrows(NoSuchMethodException.class, () -> {
            new Parser<>(TestRecord.class)
                .setRootType("INPUT")
                .addDissector(new NormalValuesDissector())
                .addDissector(new FooDissector())
                .addDissector(new BarDissector())
                .ignoreMissingDissectors()
                .addParseTarget("NoSetterWithThisName", "SOMETHING:that.is.not.present")
                .parse("Doesn't matter");
        });
    }

    @Test
    void testBadParameters() throws NoSuchMethodException, InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecord.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .addDissector(new FooDissector())
            .addDissector(new BarDissector())
            .ignoreMissingDissectors()
            .addParseTarget("setStringValue", Parser.SetterPolicy.ALWAYS, "SOMETHING:that.is.not.present")
            .addParseTarget("setStringValue", Parser.SetterPolicy.ALWAYS, "STRING:string")
            .addParseTarget("setStringValue", null)
            .addParseTarget((Method)null, "foo")
            .parse("Doesn't matter");
    }

    @Test
    void testFieldCleanup() throws NoSuchMethodException, InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecord.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .addParseTarget("setStringValue", "stRinG:stRinG")
            .parse("Doesn't matter")
            .expectString("STRING:string", "FortyTwo");
    }


}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/annotation/TestFieldSetters.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.annotation;

import nl.basjes.parse.core.Field;
import nl.basjes.parse.core.Parser;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.test.EmptyValuesDissector;
import nl.basjes.parse.core.test.NormalValuesDissector;
import nl.basjes.parse.core.test.NullValuesDissector;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

import static nl.basjes.parse.core.Parser.SetterPolicy.ALWAYS;
import static nl.basjes.parse.core.Parser.SetterPolicy.NOT_EMPTY;
import static nl.basjes.parse.core.Parser.SetterPolicy.NOT_NULL;

// CHECKSTYLE.OFF: ParenPad
// CHECKSTYLE.OFF: LeftCurly
class TestFieldSetters {

    public static class TestFieldSettersRecord extends TestRecord {
        private void setS(String prefix, String name, String value) {
            setStringValue(prefix + "-" + name, value);
        }
        private void setL(String prefix, String name, Long value) {
            setLongValue(prefix + "-" + name, value);
        }
        private void setD(String prefix, String name, Double value) {
            setDoubleValue(prefix + "-" + name, value);
        }

        @Field(value = "ANY:any"                                   ) public void setAD(String n, String v){ setS("D", n, v); }
        @Field(value = "STRING:string"                             ) public void setSD(String n, String v){ setS("D", n, v); }
        @Field(value = "INT:int"                                   ) public void setID(String n, String v){ setS("D", n, v); }
        @Field(value = "LONG:long"                                 ) public void setLD(String n, String v){ setS("D", n, v); }
        @Field(value = "FLOAT:float"                               ) public void setFD(String n, String v){ setS("D", n, v); }
        @Field(value = "DOUBLE:double"                             ) public void setDD(String n, String v){ setS("D", n, v); }
        @Field(value = "ANY:any"                                   ) public void setAD(String n, Long   v){ setL("D", n, v); }
        @Field(value = "STRING:string"                             ) public void setSD(String n, Long   v){ setL("D", n, v); }
        @Field(value = "INT:int"                                   ) public void setID(String n, Long   v){ setL("D", n, v); }
        @Field(value = "LONG:long"                                 ) public void setLD(String n, Long   v){ setL("D", n, v); }
        @Field(value = "FLOAT:float"                               ) public void setFD(String n, Long   v){ setL("D", n, v); }
        @Field(value = "DOUBLE:double"                             ) public void setDD(String n, Long   v){ setL("D", n, v); }
        @Field(value = "ANY:any"                                   ) public void setAD(String n, Double v){ setD("D", n, v); }
        @Field(value = "STRING:string"                             ) public void setSD(String n, Double v){ setD("D", n, v); }
        @Field(value = "INT:int"                                   ) public void setID(String n, Double v){ setD("D", n, v); }
        @Field(value = "LONG:long"                                 ) public void setLD(String n, Double v){ setD("D", n, v); }
        @Field(value = "FLOAT:float"                               ) public void setFD(String n, Double v){ setD("D", n, v); }
        @Field(value = "DOUBLE:double"                             ) public void setDD(String n, Double v){ setD("D", n, v); }

        @Field(value = "ANY:any",          setterPolicy = ALWAYS   ) public void setAA(String n, String v){ setS("A", n, v); }
        @Field(value = "STRING:string",    setterPolicy = ALWAYS   ) public void setSA(String n, String v){ setS("A", n, v); }
        @Field(value = "INT:int",          setterPolicy = ALWAYS   ) public void setIA(String n, String v){ setS("A", n, v); }
        @Field(value = "LONG:long",        setterPolicy = ALWAYS   ) public void setLA(String n, String v){ setS("A", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = ALWAYS   ) public void setFA(String n, String v){ setS("A", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = ALWAYS   ) public void setDA(String n, String v){ setS("A", n, v); }
        @Field(value = "ANY:any",          setterPolicy = ALWAYS   ) public void setAA(String n, Long   v){ setL("A", n, v); }
        @Field(value = "STRING:string",    setterPolicy = ALWAYS   ) public void setSA(String n, Long   v){ setL("A", n, v); }
        @Field(value = "INT:int",          setterPolicy = ALWAYS   ) public void setIA(String n, Long   v){ setL("A", n, v); }
        @Field(value = "LONG:long",        setterPolicy = ALWAYS   ) public void setLA(String n, Long   v){ setL("A", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = ALWAYS   ) public void setFA(String n, Long   v){ setL("A", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = ALWAYS   ) public void setDA(String n, Long   v){ setL("A", n, v); }
        @Field(value = "ANY:any",          setterPolicy = ALWAYS   ) public void setAA(String n, Double v){ setD("A", n, v); }
        @Field(value = "STRING:string",    setterPolicy = ALWAYS   ) public void setSA(String n, Double v){ setD("A", n, v); }
        @Field(value = "INT:int",          setterPolicy = ALWAYS   ) public void setIA(String n, Double v){ setD("A", n, v); }
        @Field(value = "LONG:long",        setterPolicy = ALWAYS   ) public void setLA(String n, Double v){ setD("A", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = ALWAYS   ) public void setFA(String n, Double v){ setD("A", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = ALWAYS   ) public void setDA(String n, Double v){ setD("A", n, v); }

        @Field(value = "ANY:any",          setterPolicy = NOT_NULL ) public void setAN(String n, String v){ setS("N", n, v); }
        @Field(value = "STRING:string",    setterPolicy = NOT_NULL ) public void setSN(String n, String v){ setS("N", n, v); }
        @Field(value = "INT:int",          setterPolicy = NOT_NULL ) public void setIN(String n, String v){ setS("N", n, v); }
        @Field(value = "LONG:long",        setterPolicy = NOT_NULL ) public void setLN(String n, String v){ setS("N", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = NOT_NULL ) public void setFN(String n, String v){ setS("N", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = NOT_NULL ) public void setDN(String n, String v){ setS("N", n, v); }
        @Field(value = "ANY:any",          setterPolicy = NOT_NULL ) public void setAN(String n, Long   v){ setL("N", n, v); }
        @Field(value = "STRING:string",    setterPolicy = NOT_NULL ) public void setSN(String n, Long   v){ setL("N", n, v); }
        @Field(value = "INT:int",          setterPolicy = NOT_NULL ) public void setIN(String n, Long   v){ setL("N", n, v); }
        @Field(value = "LONG:long",        setterPolicy = NOT_NULL ) public void setLN(String n, Long   v){ setL("N", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = NOT_NULL ) public void setFN(String n, Long   v){ setL("N", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = NOT_NULL ) public void setDN(String n, Long   v){ setL("N", n, v); }
        @Field(value = "ANY:any",          setterPolicy = NOT_NULL ) public void setAN(String n, Double v){ setD("N", n, v); }
        @Field(value = "STRING:string",    setterPolicy = NOT_NULL ) public void setSN(String n, Double v){ setD("N", n, v); }
        @Field(value = "INT:int",          setterPolicy = NOT_NULL ) public void setIN(String n, Double v){ setD("N", n, v); }
        @Field(value = "LONG:long",        setterPolicy = NOT_NULL ) public void setLN(String n, Double v){ setD("N", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = NOT_NULL ) public void setFN(String n, Double v){ setD("N", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = NOT_NULL ) public void setDN(String n, Double v){ setD("N", n, v); }

        @Field(value = "ANY:any",          setterPolicy = NOT_EMPTY) public void setAE(String n, String v){ setS("E", n, v); }
        @Field(value = "STRING:string",    setterPolicy = NOT_EMPTY) public void setSE(String n, String v){ setS("E", n, v); }
        @Field(value = "INT:int",          setterPolicy = NOT_EMPTY) public void setIE(String n, String v){ setS("E", n, v); }
        @Field(value = "LONG:long",        setterPolicy = NOT_EMPTY) public void setLE(String n, String v){ setS("E", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = NOT_EMPTY) public void setFE(String n, String v){ setS("E", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = NOT_EMPTY) public void setDE(String n, String v){ setS("E", n, v); }
        @Field(value = "ANY:any",          setterPolicy = NOT_EMPTY) public void setAE(String n, Long   v){ setL("E", n, v); }
        @Field(value = "STRING:string",    setterPolicy = NOT_EMPTY) public void setSE(String n, Long   v){ setL("E", n, v); }
        @Field(value = "INT:int",          setterPolicy = NOT_EMPTY) public void setIE(String n, Long   v){ setL("E", n, v); }
        @Field(value = "LONG:long",        setterPolicy = NOT_EMPTY) public void setLE(String n, Long   v){ setL("E", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = NOT_EMPTY) public void setFE(String n, Long   v){ setL("E", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = NOT_EMPTY) public void setDE(String n, Long   v){ setL("E", n, v); }
        @Field(value = "ANY:any",          setterPolicy = NOT_EMPTY) public void setAE(String n, Double v){ setD("E", n, v); }
        @Field(value = "STRING:string",    setterPolicy = NOT_EMPTY) public void setSE(String n, Double v){ setD("E", n, v); }
        @Field(value = "INT:int",          setterPolicy = NOT_EMPTY) public void setIE(String n, Double v){ setD("E", n, v); }
        @Field(value = "LONG:long",        setterPolicy = NOT_EMPTY) public void setLE(String n, Double v){ setD("E", n, v); }
        @Field(value = "FLOAT:float",      setterPolicy = NOT_EMPTY) public void setFE(String n, Double v){ setD("E", n, v); }
        @Field(value = "DOUBLE:double",    setterPolicy = NOT_EMPTY) public void setDE(String n, Double v){ setD("E", n, v); }
    }

    @Test
    void testNormalValues() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestFieldSettersRecord.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .parse("Doesn't matter")

            // Default (== Always)
            .expectString(  "D-ANY:any",        "42")
            .expectString(  "D-STRING:string",  "FortyTwo")
            .expectString(  "D-INT:int",        "42")
            .expectString(  "D-LONG:long",      "42")
            .expectString(  "D-FLOAT:float",    "42.0")
            .expectString(  "D-DOUBLE:double",  "42.0")
            .expectLong(    "D-ANY:any",        42L)
            .noLong(     "D-STRING:string")
            .expectLong(    "D-INT:int",        42L)
            .expectLong(    "D-LONG:long",      42L)
            .noLong(     "D-FLOAT:float")
            .noLong(     "D-DOUBLE:double")
            .expectDouble(  "D-ANY:any",        42D)
            .noDouble(   "D-STRING:string")
            .noDouble(   "D-INT:int")
            .noDouble(   "D-LONG:long")
            .expectDouble(  "D-FLOAT:float",    42D)
            .expectDouble(  "D-DOUBLE:double",  42D)

            // Always
            .expectString(  "A-ANY:any",        "42")
            .expectString(  "A-STRING:string",  "FortyTwo")
            .expectString(  "A-INT:int",        "42")
            .expectString(  "A-LONG:long",      "42")
            .expectString(  "A-FLOAT:float",    "42.0")
            .expectString(  "A-DOUBLE:double",  "42.0")
            .expectLong(    "A-ANY:any",        42L)
            .noLong(     "A-STRING:string")
            .expectLong(    "A-INT:int",        42L)
            .expectLong(    "A-LONG:long",      42L)
            .noLong(     "A-FLOAT:float")
            .noLong(     "A-DOUBLE:double")
            .expectDouble(  "A-ANY:any",        42D)
            .noDouble(   "A-STRING:string")
            .noDouble(   "A-INT:int")
            .noDouble(   "A-LONG:long")
            .expectDouble(  "A-FLOAT:float",    42D)
            .expectDouble(  "A-DOUBLE:double",  42D)

            // Not Null
            .expectString(  "N-ANY:any",        "42")
            .expectString(  "N-STRING:string",  "FortyTwo")
            .expectString(  "N-INT:int",        "42")
            .expectString(  "N-LONG:long",      "42")
            .expectString(  "N-FLOAT:float",    "42.0")
            .expectString(  "N-DOUBLE:double",  "42.0")
            .expectLong(    "N-ANY:any",        42L)
            .noLong(     "N-STRING:string")
            .expectLong(    "N-INT:int",        42L)
            .expectLong(    "N-LONG:long",      42L)
            .noLong(     "N-FLOAT:float")
            .noLong(     "N-DOUBLE:double")
            .expectDouble(  "N-ANY:any",        42D)
            .noDouble(   "N-STRING:string")
            .noDouble(   "N-INT:int")
            .noDouble(   "N-LONG:long")
            .expectDouble(  "N-FLOAT:float",    42D)
            .expectDouble(  "N-DOUBLE:double",  42D)

            // Not Empty
            .expectString(  "E-ANY:any",        "42")
            .expectString(  "E-STRING:string",  "FortyTwo")
            .expectString(  "E-INT:int",        "42")
            .expectString(  "E-LONG:long",      "42")
            .expectString(  "E-FLOAT:float",    "42.0")
            .expectString(  "E-DOUBLE:double",  "42.0")
            .expectLong(    "E-ANY:any",        42L)
            .noLong(     "E-STRING:string")
            .expectLong(    "E-INT:int",        42L)
            .expectLong(    "E-LONG:long",      42L)
            .noLong(     "E-FLOAT:float")
            .noLong(     "E-DOUBLE:double")
            .expectDouble(  "E-ANY:any",        42D)
            .noDouble(   "E-STRING:string")
            .noDouble(   "E-INT:int")
            .noDouble(   "E-LONG:long")
            .expectDouble(  "E-FLOAT:float",    42D)
            .expectDouble(  "E-DOUBLE:double",  42D);
    }

    @Test
    void testEmptyValues() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        Parser parser = new Parser<>(TestFieldSettersRecord.class);
        parser.setRootType("INPUT");
        parser.addDissector(new EmptyValuesDissector());
        TestFieldSettersRecord testRecord = parser.parse("Doesn't matter");

        testRecord
            // Default (== Always)
            .expectString(  "D-ANY:any",        "")
            .expectString(  "D-STRING:string",  "")
            .expectString(  "D-INT:int",        "")
            .expectString(  "D-LONG:long",      "")
            .expectString(  "D-FLOAT:float",    "")
            .expectString(  "D-DOUBLE:double",  "")
            .expectLong(    "D-ANY:any",        (Long)null)
            .noLong(     "D-STRING:string")
            .expectLong(    "D-INT:int",        (Long)null)
            .expectLong(    "D-LONG:long",      (Long)null)
            .noLong(     "D-FLOAT:float")
            .noLong(     "D-DOUBLE:double")
            .expectDouble(  "D-ANY:any",        (Double)null)
            .noDouble(   "D-STRING:string")
            .noDouble(   "D-INT:int")
            .noDouble(   "D-LONG:long")
            .expectDouble(  "D-FLOAT:float",    (Double)null)
            .expectDouble(  "D-DOUBLE:double",  (Double)null)

            // Always
            .expectString(  "A-ANY:any",        "")
            .expectString(  "A-STRING:string",  "")
            .expectString(  "A-INT:int",        "")
            .expectString(  "A-LONG:long",      "")
            .expectString(  "A-FLOAT:float",    "")
            .expectString(  "A-DOUBLE:double",  "")
            .expectLong(    "A-ANY:any",        (Long)null)
            .noLong(     "A-STRING:string")
            .expectLong(    "A-INT:int",        (Long)null)
            .expectLong(    "A-LONG:long",      (Long)null)
            .noLong(     "A-FLOAT:float")
            .noLong(     "A-DOUBLE:double")
            .expectDouble(  "A-ANY:any",        (Double)null)
            .noDouble(   "A-STRING:string")
            .noDouble(   "A-INT:int")
            .noDouble(   "A-LONG:long")
            .expectDouble(  "A-FLOAT:float",    (Double)null)
            .expectDouble(  "A-DOUBLE:double",  (Double)null)

            // Not Null
            .expectString(  "N-ANY:any",        "")
            .expectString(  "N-STRING:string",  "")
            .expectString(  "N-INT:int",        "")
            .expectString(  "N-LONG:long",      "")
            .expectString(  "N-FLOAT:float",    "")
            .expectString(  "N-DOUBLE:double",  "")
            .noLong(     "N-ANY:any")
            .noLong(     "N-STRING:string")
            .noLong(     "N-INT:int")
            .noLong(     "N-LONG:long")
            .noLong(     "N-FLOAT:float")
            .noLong(     "N-DOUBLE:double")
            .noDouble(   "N-ANY:any")
            .noDouble(   "N-STRING:string")
            .noDouble(   "N-INT:int")
            .noDouble(   "N-LONG:long")
            .noDouble(   "N-FLOAT:float")
            .noDouble(   "N-DOUBLE:double")

            // Not Empty
            .noString(  "E-ANY:any")
            .noString(  "E-STRING:string")
            .noString(  "E-INT:int")
            .noString(  "E-LONG:long")
            .noString(  "E-FLOAT:float")
            .noString(  "E-DOUBLE:double")
            .noLong(    "E-ANY:any")
            .noLong(    "E-STRING:string")
            .noLong(    "E-INT:int")
            .noLong(    "E-LONG:long")
            .noLong(    "E-FLOAT:float")
            .noLong(    "E-DOUBLE:double")
            .noDouble(  "E-ANY:any")
            .noDouble(  "E-STRING:string")
            .noDouble(  "E-INT:int")
            .noDouble(  "E-LONG:long")
            .noDouble(  "E-FLOAT:float")
            .noDouble(  "E-DOUBLE:double");

    }

    @Test
    void testNullValues() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        Parser parser = new Parser<>(TestFieldSettersRecord.class);
        parser.setRootType("INPUT");
        parser.addDissector(new NullValuesDissector());
        TestFieldSettersRecord testRecord = parser.parse("Doesn't matter");

        testRecord
            // Default (== Always)
            .expectString(  "D-ANY:any",        (String)null)
            .expectString(  "D-STRING:string",  (String)null)
            .expectString(  "D-INT:int",        (String)null)
            .expectString(  "D-LONG:long",      (String)null)
            .expectString(  "D-FLOAT:float",    (String)null)
            .expectString(  "D-DOUBLE:double",  (String)null)
            .expectLong(    "D-ANY:any",        (Long)null)
            .noLong(     "D-STRING:string")
            .expectLong(    "D-INT:int",        (Long)null)
            .expectLong(    "D-LONG:long",      (Long)null)
            .noLong(     "D-FLOAT:float")
            .noLong(     "D-DOUBLE:double")
            .expectDouble(  "D-ANY:any",        (Double)null)
            .noDouble(   "D-STRING:string")
            .noDouble(   "D-INT:int")
            .noDouble(   "D-LONG:long")
            .expectDouble(  "D-FLOAT:float",    (Double)null)
            .expectDouble(  "D-DOUBLE:double",  (Double)null)

            // Always
            .expectString(  "A-ANY:any",        (String)null)
            .expectString(  "A-STRING:string",  (String)null)
            .expectString(  "A-INT:int",        (String)null)
            .expectString(  "A-LONG:long",      (String)null)
            .expectString(  "A-FLOAT:float",    (String)null)
            .expectString(  "A-DOUBLE:double",  (String)null)
            .expectLong(    "A-ANY:any",        (Long)null)
            .noLong(     "A-STRING:string")
            .expectLong(    "A-INT:int",        (Long)null)
            .expectLong(    "A-LONG:long",      (Long)null)
            .noLong(     "A-FLOAT:float")
            .noLong(     "A-DOUBLE:double")
            .expectDouble(  "A-ANY:any",        (Double)null)
            .noDouble(   "A-STRING:string")
            .noDouble(   "A-INT:int")
            .noDouble(   "A-LONG:long")
            .expectDouble(  "A-FLOAT:float",    (Double)null)
            .expectDouble(  "A-DOUBLE:double",  (Double)null)

            // Not Null
            .noString(  "N-ANY:any")
            .noString(  "N-STRING:string")
            .noString(  "N-INT:int")
            .noString(  "N-LONG:long")
            .noString(  "N-FLOAT:float")
            .noString(  "N-DOUBLE:double")
            .noLong(    "N-ANY:any")
            .noLong(    "N-STRING:string")
            .noLong(    "N-INT:int")
            .noLong(    "N-LONG:long")
            .noLong(    "N-FLOAT:float")
            .noLong(    "N-DOUBLE:double")
            .noDouble(  "N-ANY:any")
            .noDouble(  "N-STRING:string")
            .noDouble(  "N-INT:int")
            .noDouble(  "N-LONG:long")
            .noDouble(  "N-FLOAT:float")
            .noDouble(  "N-DOUBLE:double")

            // Not Empty
            .noString(  "E-ANY:any")
            .noString(  "E-STRING:string")
            .noString(  "E-INT:int")
            .noString(  "E-LONG:long")
            .noString(  "E-FLOAT:float")
            .noString(  "E-DOUBLE:double")
            .noLong(    "E-ANY:any")
            .noLong(    "E-STRING:string")
            .noLong(    "E-INT:int")
            .noLong(    "E-LONG:long")
            .noLong(    "E-FLOAT:float")
            .noLong(    "E-DOUBLE:double")
            .noDouble(  "E-ANY:any")
            .noDouble(  "E-STRING:string")
            .noDouble(  "E-INT:int")
            .noDouble(  "E-LONG:long")
            .noDouble(  "E-FLOAT:float")
            .noDouble(  "E-DOUBLE:double");
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/annotation/TestFieldSettersAlwaysCombined.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.annotation;

import nl.basjes.parse.core.Field;
import nl.basjes.parse.core.Parser;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.test.NormalValuesDissector;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

import static nl.basjes.parse.core.Parser.SetterPolicy.ALWAYS;

class TestFieldSettersAlwaysCombined {

    public static class TestRecordString extends TestRecord {
        @Field(value = {
            "ANY:any",
            "STRING:string",
            "INT:int",
            "LONG:long",
            "FLOAT:float",
            "DOUBLE:double" },
            setterPolicy = ALWAYS)
        public void set(String name, String value) {
            setStringValue(name, value);
        }
    }

    public static class TestRecordLong  extends TestRecord {
        @Field(value = {
            "ANY:any",
            "INT:int",
            "LONG:long" },
            setterPolicy = ALWAYS)
        public void set(String name, Long value) {
            setLongValue(name, value);
        }
    }

    public static class TestRecordDouble  extends TestRecord {
        @Field(value = {
            "ANY:any",
            "FLOAT:float",
            "DOUBLE:double" },
            setterPolicy = ALWAYS)
        public void set(String name, Double value) {
            setDoubleValue(name, value);
        }
    }


    @Test
    void testString() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordString.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .parse("Doesn't matter")

            .expectString("ANY:any",       "42")
            .expectString("STRING:string", "FortyTwo")
            .expectString("INT:int",       "42")
            .expectString("LONG:long",     "42")
            .expectString("FLOAT:float",   "42.0")
            .expectString("DOUBLE:double", "42.0");
    }

    @Test
    void testLong() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordLong.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .parse("Doesn't matter")

            .expectLong("ANY:any",    42L)
            .expectLong("INT:int",    42L)
            .expectLong("LONG:long",  42L);
    }

    @Test
    void testDouble() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordDouble.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .parse("Doesn't matter")

            .expectDouble("ANY:any",       42D)
            .expectDouble("FLOAT:float",   42D)
            .expectDouble("DOUBLE:double", 42D);
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/annotation/TestFieldSettersAlwaysSeparate.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.annotation;

import nl.basjes.parse.core.Field;
import nl.basjes.parse.core.Parser;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.test.NormalValuesDissector;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

import static nl.basjes.parse.core.Parser.SetterPolicy.ALWAYS;

public class TestFieldSettersAlwaysSeparate {

    public static class TestRecordString extends TestRecord {
        private void set(String name, String value) {
            setStringValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = ALWAYS) public void setA(String n, String v) { set(n, v); }
        @Field(value = "STRING:string", setterPolicy = ALWAYS) public void setS(String n, String v) { set(n, v); }
        @Field(value = "INT:int",       setterPolicy = ALWAYS) public void setI(String n, String v) { set(n, v); }
        @Field(value = "LONG:long",     setterPolicy = ALWAYS) public void setL(String n, String v) { set(n, v); }
        @Field(value = "FLOAT:float",   setterPolicy = ALWAYS) public void setF(String n, String v) { set(n, v); }
        @Field(value = "DOUBLE:double", setterPolicy = ALWAYS) public void setD(String n, String v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    public static class TestRecordLong extends TestRecord {
        private void set(String name, Long value) {
            setLongValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = ALWAYS) public void setA(String n, Long v) { set(n, v); }
        @Field(value = "INT:int",       setterPolicy = ALWAYS) public void setI(String n, Long v) { set(n, v); }
        @Field(value = "LONG:long",     setterPolicy = ALWAYS) public void setL(String n, Long v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    public static class TestRecordDouble extends TestRecord {
        private void set(String name, Double value) {
            setDoubleValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = ALWAYS) public void setA(String n, Double v) { set(n, v); }
        @Field(value = "FLOAT:float",   setterPolicy = ALWAYS) public void setF(String n, Double v) { set(n, v); }
        @Field(value = "DOUBLE:double", setterPolicy = ALWAYS) public void setD(String n, Double v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    @Test
    void testString() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordString.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .parse("Doesn't matter")

            .expectString("ANY:any",       "42")
            .expectString("STRING:string", "FortyTwo")
            .expectString("INT:int",       "42")
            .expectString("LONG:long",     "42")
            .expectString("FLOAT:float",   "42.0")
            .expectString("DOUBLE:double", "42.0");
    }

    @Test
    void testLong() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordLong.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .parse("Doesn't matter")

            .expectLong("ANY:any",    42L)
            .expectLong("INT:int",    42L)
            .expectLong("LONG:long",  42L);
    }

    @Test
    void testDouble() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordDouble.class)
            .setRootType("INPUT")
            .addDissector(new NormalValuesDissector())
            .parse("Doesn't matter")

            .expectDouble("ANY:any",       42D)
            .expectDouble("FLOAT:float",   42D)
            .expectDouble("DOUBLE:double", 42D);
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/annotation/TestFieldSettersNotEmpty.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.annotation;

import nl.basjes.parse.core.Field;
import nl.basjes.parse.core.Parser;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.test.EmptyValuesDissector;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

import static nl.basjes.parse.core.Parser.SetterPolicy.NOT_EMPTY;

public class TestFieldSettersNotEmpty {

    public static class TestRecordString extends TestRecord {
        @Field(value = {
            "ANY:any",
            "STRING:string",
            "INT:int",
            "LONG:long",
            "FLOAT:float",
            "DOUBLE:double" },
            setterPolicy = NOT_EMPTY)
        public void set(String name, String value) {
            setStringValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = NOT_EMPTY) public void setA(String n, String v) { set(n, v); }
        @Field(value = "STRING:string", setterPolicy = NOT_EMPTY) public void setS(String n, String v) { set(n, v); }
        @Field(value = "INT:int",       setterPolicy = NOT_EMPTY) public void setI(String n, String v) { set(n, v); }
        @Field(value = "LONG:long",     setterPolicy = NOT_EMPTY) public void setL(String n, String v) { set(n, v); }
        @Field(value = "FLOAT:float",   setterPolicy = NOT_EMPTY) public void setF(String n, String v) { set(n, v); }
        @Field(value = "DOUBLE:double", setterPolicy = NOT_EMPTY) public void setD(String n, String v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    public static class TestRecordLong extends TestRecord {
        @Field(value = {
            "ANY:any",
            "INT:int",
            "LONG:long" },
            setterPolicy = NOT_EMPTY)
        public void set(String name, Long value) {
            setLongValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = NOT_EMPTY) public void setA(String n, Long v) { set(n, v); }
        @Field(value = "INT:int",       setterPolicy = NOT_EMPTY) public void setI(String n, Long v) { set(n, v); }
        @Field(value = "LONG:long",     setterPolicy = NOT_EMPTY) public void setL(String n, Long v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    public static class TestRecordDouble extends TestRecord {
        @Field(value = {
            "ANY:any",
            "FLOAT:float",
            "DOUBLE:double" },
            setterPolicy = NOT_EMPTY)
        public void set(String name, Double value) {
            setDoubleValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = NOT_EMPTY) public void setA(String n, Double v) { set(n, v); }
        @Field(value = "FLOAT:float",   setterPolicy = NOT_EMPTY) public void setF(String n, Double v) { set(n, v); }
        @Field(value = "DOUBLE:double", setterPolicy = NOT_EMPTY) public void setD(String n, Double v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    @Test
    void testString() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordString.class)
            .setRootType("INPUT")
            .addDissector(new EmptyValuesDissector())
            .parse("Doesn't matter")

            .noString("ANY:any")
            .noString("STRING:string")
            .noString("INT:int")
            .noString("LONG:long")
            .noString("FLOAT:float")
            .noString("DOUBLE:double");
    }

    @Test
    void testLong() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordLong.class)
            .setRootType("INPUT")
            .addDissector(new EmptyValuesDissector())
            .parse("Doesn't matter")

            .noLong("ANY:any")
            .noLong("INT:int")
            .noLong("LONG:long");
    }

    @Test
    void testDouble() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordDouble.class)
            .setRootType("INPUT")
            .addDissector(new EmptyValuesDissector())
            .parse("Doesn't matter")

            .noDouble("ANY:any")
            .noDouble("FLOAT:float")
            .noDouble("DOUBLE:double");
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/annotation/TestFieldSettersNotNull.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.annotation;

import nl.basjes.parse.core.Field;
import nl.basjes.parse.core.Parser;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import nl.basjes.parse.core.test.NullValuesDissector;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

import static nl.basjes.parse.core.Parser.SetterPolicy.NOT_NULL;

public class TestFieldSettersNotNull {

    public static class TestRecordString extends TestRecord {
        @Field(value = {
            "ANY:any",
            "STRING:string",
            "INT:int",
            "LONG:long",
            "FLOAT:float",
            "DOUBLE:double" },
            setterPolicy = NOT_NULL)
        public void set(String name, String value) {
            setStringValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = NOT_NULL) public void setA(String n, String v) { set(n, v); }
        @Field(value = "STRING:string", setterPolicy = NOT_NULL) public void setS(String n, String v) { set(n, v); }
        @Field(value = "INT:int",       setterPolicy = NOT_NULL) public void setI(String n, String v) { set(n, v); }
        @Field(value = "LONG:long",     setterPolicy = NOT_NULL) public void setL(String n, String v) { set(n, v); }
        @Field(value = "FLOAT:float",   setterPolicy = NOT_NULL) public void setF(String n, String v) { set(n, v); }
        @Field(value = "DOUBLE:double", setterPolicy = NOT_NULL) public void setD(String n, String v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    public static class TestRecordLong extends TestRecord {
        @Field(value = {
            "ANY:any",
            "INT:int",
            "LONG:long" },
            setterPolicy = NOT_NULL)
        public void set(String name, Long value) {
            setLongValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = NOT_NULL) public void setA(String n, Long v) { set(n, v); }
        @Field(value = "INT:int",       setterPolicy = NOT_NULL) public void setI(String n, Long v) { set(n, v); }
        @Field(value = "LONG:long",     setterPolicy = NOT_NULL) public void setL(String n, Long v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    public static class TestRecordDouble extends TestRecord {
        @Field(value = {
            "ANY:any",
            "FLOAT:float",
            "DOUBLE:double" },
            setterPolicy = NOT_NULL)
        public void set(String name, Double value) {
            setDoubleValue(name, value);
        }

        // CHECKSTYLE.OFF: LeftCurly
        @Field(value = "ANY:any",       setterPolicy = NOT_NULL) public void setA(String n, Double v) { set(n, v); }
        @Field(value = "FLOAT:float",   setterPolicy = NOT_NULL) public void setF(String n, Double v) { set(n, v); }
        @Field(value = "DOUBLE:double", setterPolicy = NOT_NULL) public void setD(String n, Double v) { set(n, v); }
        // CHECKSTYLE.ON: LeftCurly
    }

    @Test
    void testString() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordString.class)
            .setRootType("INPUT")
            .addDissector(new NullValuesDissector())
            .parse("Doesn't matter")

            .noString("ANY:any")
            .noString("STRING:string")
            .noString("INT:int")
            .noString("LONG:long")
            .noString("FLOAT:float")
            .noString("DOUBLE:double");
    }

    @Test
    void testLong() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordLong.class)
            .setRootType("INPUT")
            .addDissector(new NullValuesDissector())
            .parse("Doesn't matter")

            .noLong("ANY:any")
            .noLong("INT:int")
            .noLong("LONG:long");
    }

    @Test
    void testDouble() throws InvalidDissectorException, MissingDissectorsException, DissectionFailure {
        new Parser<>(TestRecordDouble.class)
            .setRootType("INPUT")
            .addDissector(new NullValuesDissector())
            .parse("Doesn't matter")

            .noDouble("ANY:any")
            .noDouble("FLOAT:float")
            .noDouble("DOUBLE:double");
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/convert/ValueConvertTest.java
================================================
/*
 * Apache HTTPD logparsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.convert;

import nl.basjes.parse.core.Casts;
import nl.basjes.parse.core.Dissector;
import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.SimpleDissector;
import nl.basjes.parse.core.Value;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.test.DissectorTester;
import org.junit.jupiter.api.Test;

import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;

import static nl.basjes.parse.core.Casts.STRING_OR_LONG;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ValueConvertTest {

    @Test
    public void verifyTypeConversionStoM() {
        DissectorTester.create()
            .withDissector("something", new SecondsToMilliseconds())
            .withDissector(new MillisecondsToSeconds())
            .withInput("12345") // Which is in seconds because that dissector is 'first'
            .expect("SECONDS:something", "12345")
            .expect("MILLISECONDS:something", "12345000")
//            .verbose()
            .checkExpectations();
    }

    @Test
    public void verifyTypeConversionMtoS() {
        DissectorTester.create()
            .withDissector("something", new MillisecondsToSeconds())
            .withDissector(new SecondsToMilliseconds())
            .withInput("12345000") // Which is in MILLIseconds because that dissector is 'first'
            .expect("SECONDS:something", "12345")
            .expect("MILLISECONDS:something", "12345000")
//            .verbose()
            .checkExpectations();
    }

    @Test
    public void verifyTypeConversionPossibleFields() {
        List possible = DissectorTester.create()
            .withDissector("something", new MillisecondsToSeconds())
            .withDissector(new SecondsToMilliseconds())
            .withInput("12345000") // Which is in MILLIseconds because that dissector is 'first'
            .getPossible();

        assertTrue(possible.contains("MILLISECONDS:something"));
        assertTrue(possible.contains("SECONDS:something"));
    }

    public abstract static class TypeConvertBaseDissector extends SimpleDissector {
        protected String inputType;
        protected String outputType;

        private static HashMap> fillOutputConfig(String outputType, EnumSet casts) {
            HashMap> typeConvertConfig = new HashMap<>();
            typeConvertConfig.put(outputType + ":", casts);
            return typeConvertConfig;
        }

        public TypeConvertBaseDissector(String nInputType, String nOutputType) {
            super(nInputType, fillOutputConfig(nOutputType, STRING_OR_LONG));
            inputType = nInputType;
            outputType = nOutputType;
        }

        @Override
        protected void initializeNewInstance(Dissector newInstance) throws InvalidDissectorException {
            super.initializeNewInstance(newInstance);
            ((TypeConvertBaseDissector) newInstance).inputType = inputType;
            ((TypeConvertBaseDissector) newInstance).outputType = outputType;
        }
    }

    public static class SecondsToMilliseconds extends TypeConvertBaseDissector {

        public SecondsToMilliseconds() {
            super("SECONDS", "MILLISECONDS");
        }

        @Override
        public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
            parsable.addDissection(inputname, "MILLISECONDS", "", value.getLong() * 1000);
        }
    }

    public static class MillisecondsToSeconds extends TypeConvertBaseDissector {
        public MillisecondsToSeconds() {
            super("MILLISECONDS", "SECONDS");
        }

        @Override
        public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
            parsable.addDissection(inputname, "SECONDS", "", value.getLong() / 1000);
        }
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/reference/BarDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.reference;

import nl.basjes.parse.core.Casts;
import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.SimpleDissector;
import nl.basjes.parse.core.Value;
import nl.basjes.parse.core.exceptions.DissectionFailure;

import java.util.EnumSet;
import java.util.HashMap;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static nl.basjes.parse.core.Casts.STRING_OR_DOUBLE;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG_OR_DOUBLE;

public class BarDissector extends SimpleDissector {

    private static final HashMap> DISSECTOR_CONFIG = new HashMap<>();
    static {
        DISSECTOR_CONFIG.put("ANY:barany",         STRING_OR_LONG_OR_DOUBLE);
        DISSECTOR_CONFIG.put("STRING:barstring",   STRING_ONLY);
        DISSECTOR_CONFIG.put("INT:barint",         STRING_OR_LONG);
        DISSECTOR_CONFIG.put("LONG:barlong",       STRING_OR_LONG);
        DISSECTOR_CONFIG.put("FLOAT:barfloat",     STRING_OR_DOUBLE);
        DISSECTOR_CONFIG.put("DOUBLE:bardouble",   STRING_OR_DOUBLE);
    }

    public BarDissector() {
        super("BARINPUT", DISSECTOR_CONFIG);
    }

    @Override
    public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
        parsable.addDissection(inputname, "ANY",    "barany",    "42");
        parsable.addDissection(inputname, "STRING", "barstring", "42");
        parsable.addDissection(inputname, "INT",    "barint",    42);
        parsable.addDissection(inputname, "LONG",   "barlong",   42L);
        parsable.addDissection(inputname, "FLOAT",  "barfloat",  42F);
        parsable.addDissection(inputname, "DOUBLE", "bardouble", 42D);
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/reference/FooDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.reference;

import nl.basjes.parse.core.Casts;
import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.SimpleDissector;
import nl.basjes.parse.core.Value;
import nl.basjes.parse.core.exceptions.DissectionFailure;

import java.util.EnumSet;
import java.util.HashMap;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static nl.basjes.parse.core.Casts.STRING_OR_DOUBLE;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG_OR_DOUBLE;

public class FooDissector extends SimpleDissector {

    private static final HashMap> DISSECTOR_CONFIG = new HashMap<>();
    static {
        DISSECTOR_CONFIG.put("ANY:fooany",         STRING_OR_LONG_OR_DOUBLE);
        DISSECTOR_CONFIG.put("STRING:foostring",   STRING_ONLY);
        DISSECTOR_CONFIG.put("INT:fooint",         STRING_OR_LONG);
        DISSECTOR_CONFIG.put("LONG:foolong",       STRING_OR_LONG);
        DISSECTOR_CONFIG.put("FLOAT:foofloat",     STRING_OR_DOUBLE);
        DISSECTOR_CONFIG.put("DOUBLE:foodouble",   STRING_OR_DOUBLE);
    }

    public FooDissector() {
        super("FOOINPUT", DISSECTOR_CONFIG);
    }

    @Override
    public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
        parsable.addDissection(inputname, "ANY",    "fooany",    "42");
        parsable.addDissection(inputname, "STRING", "foostring", "42");
        parsable.addDissection(inputname, "INT",    "fooint",    42);
        parsable.addDissection(inputname, "LONG",   "foolong",   42L);
        parsable.addDissection(inputname, "FLOAT",  "foofloat",  42F);
        parsable.addDissection(inputname, "DOUBLE", "foodouble", 42D);
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/reference/FooSpecialDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.reference;

import nl.basjes.parse.core.Parser;

public class FooSpecialDissector extends FooDissector {
    @Override
    public  void createAdditionalDissectors(Parser parser) {
        parser.addDissector(new BarDissector());
        parser.addTypeRemapping("foostring", "BARINPUT");
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/reference/ReferenceTest.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.reference;

import nl.basjes.parse.core.Parser;
import nl.basjes.parse.core.test.DissectorTester;
import nl.basjes.parse.core.test.TestRecord;
import org.junit.jupiter.api.Test;

public class ReferenceTest {

    @Test
    public void verifyFoo() {
        DissectorTester.create()
            .withDissector(new FooDissector())
            .withInput("Doesn't matter")
            .expect("ANY:fooany",        "42")
            .expect("ANY:fooany",        42L)
            .expect("ANY:fooany",        42D)
            .expect("STRING:foostring",  "42")
            .expectAbsentLong("STRING:foostring")
            .expectAbsentDouble("STRING:foostring")
            .expect("INT:fooint",        "42")
            .expect("INT:fooint",        42L)
            .expectAbsentDouble("INT:fooint")
            .expect("LONG:foolong",      "42")
            .expect("LONG:foolong",      42L)
            .expectAbsentDouble("LONG:foolong")
            .expect("FLOAT:foofloat",    "42.0")
            .expectAbsentLong("FLOAT:foofloat")
            .expect("FLOAT:foofloat",    42D)
            .expect("DOUBLE:foodouble",  "42.0")
            .expectAbsentLong("DOUBLE:foodouble")
            .expect("DOUBLE:foodouble",  42D)
//            .verbose()
            .checkExpectations();
    }

    @Test
    public void verifyBar() {
        DissectorTester.create()
            .withDissector(new BarDissector())
            .withInput("Doesn't matter")
            .expect("ANY:barany",        "42")
            .expect("ANY:barany",        42L)
            .expect("ANY:barany",        42D)
            .expect("STRING:barstring",  "42")
            .expectAbsentLong("STRING:barstring")
            .expectAbsentDouble("STRING:barstring")
            .expect("INT:barint",        "42")
            .expect("INT:barint",        42L)
            .expectAbsentDouble("INT:barint")
            .expect("LONG:barlong",      "42")
            .expect("LONG:barlong",      42L)
            .expectAbsentDouble("LONG:barlong")
            .expect("FLOAT:barfloat",    "42.0")
            .expectAbsentLong("FLOAT:barfloat")
            .expect("FLOAT:barfloat",    42D)
            .expect("DOUBLE:bardouble",  "42.0")
            .expectAbsentLong("DOUBLE:bardouble")
            .expect("DOUBLE:bardouble",  42D)
//            .verbose()
            .checkExpectations();
    }

    @Test
    public void runManuallyCombined(){
        Parser parser = new Parser<>(TestRecord.class);
        parser.addDissector(new FooDissector());
        parser.addDissector(new BarDissector());
        parser.addTypeRemapping("foostring", "BARINPUT");
        parser.setRootType(new FooDissector().getInputType());

        DissectorTester.create()
            .withParser(parser)
            .withInput("BlaBlaBla")

            .expect("ANY:fooany",                   "42")
            .expect("ANY:fooany",                   42L)
            .expect("ANY:fooany",                   42D)
            .expect("STRING:foostring",             "42")
            .expectAbsentLong("STRING:foostring")
            .expectAbsentDouble("STRING:foostring")
            .expect("INT:fooint",                   "42")
            .expect("INT:fooint",                   42L)
            .expectAbsentDouble("INT:fooint")
            .expect("LONG:foolong",                 "42")
            .expect("LONG:foolong",                 42L)
            .expectAbsentDouble("LONG:foolong")
            .expect("FLOAT:foofloat",               "42.0")
            .expectAbsentLong("FLOAT:foofloat")
            .expect("FLOAT:foofloat",               42D)
            .expect("DOUBLE:foodouble",             "42.0")
            .expectAbsentLong("DOUBLE:foodouble")
            .expect("DOUBLE:foodouble",             42D)

            .expect("ANY:foostring.barany",         "42")
            .expect("ANY:foostring.barany",         42L)
            .expect("ANY:foostring.barany",         42D)
            .expect("STRING:foostring.barstring",   "42")
            .expectAbsentLong("STRING:foostring.barstring")
            .expectAbsentDouble("STRING:foostring.barstring")
            .expect("INT:foostring.barint",         "42")
            .expect("INT:foostring.barint",         42L)
            .expectAbsentDouble("INT:foostring.barint")
            .expect("LONG:foostring.barlong",       "42")
            .expect("LONG:foostring.barlong",       42L)
            .expectAbsentDouble("LONG:foostring.barlong")
            .expect("FLOAT:foostring.barfloat",     "42.0")
            .expectAbsentLong("FLOAT:foostring.barfloat")
            .expect("FLOAT:foostring.barfloat",     42D)
            .expect("DOUBLE:foostring.bardouble",   "42.0")
            .expectAbsentLong("DOUBLE:foostring.bardouble")
            .expect("DOUBLE:foostring.bardouble",   42D)

            .checkExpectations();
    }

    @Test
    public void runAutomaticallyAddedBar(){
        DissectorTester.create()
            .withDissector(new FooSpecialDissector())
            .withInput("BlaBlaBla")

            .expect("ANY:fooany",                   "42")
            .expect("ANY:fooany",                   42L)
            .expect("ANY:fooany",                   42D)
            .expect("STRING:foostring",             "42")
            .expectAbsentLong("STRING:foostring")
            .expectAbsentDouble("STRING:foostring")
            .expect("INT:fooint",                 "42")
            .expect("INT:fooint",                 42L)
            .expectAbsentDouble("INT:fooint")
            .expect("LONG:foolong",                 "42")
            .expect("LONG:foolong",                 42L)
            .expectAbsentDouble("LONG:foolong")
            .expect("FLOAT:foofloat",             "42.0")
            .expectAbsentLong("FLOAT:foofloat")
            .expect("FLOAT:foofloat",             42D)
            .expect("DOUBLE:foodouble",             "42.0")
            .expectAbsentLong("DOUBLE:foodouble")
            .expect("DOUBLE:foodouble",             42D)

            .expect("ANY:foostring.barany",         "42")
            .expect("ANY:foostring.barany",         42L)
            .expect("ANY:foostring.barany",         42D)
            .expect("STRING:foostring.barstring",   "42")
            .expectAbsentLong("STRING:foostring.barstring")
            .expectAbsentDouble("STRING:foostring.barstring")
            .expect("INT:foostring.barint",       "42")
            .expect("INT:foostring.barint",       42L)
            .expectAbsentDouble("INT:foostring.barint")
            .expect("LONG:foostring.barlong",       "42")
            .expect("LONG:foostring.barlong",       42L)
            .expectAbsentDouble("LONG:foostring.barlong")
            .expect("FLOAT:foostring.barfloat",   "42.0")
            .expectAbsentLong("FLOAT:foostring.barfloat")
            .expect("FLOAT:foostring.barfloat",   42D)
            .expect("DOUBLE:foostring.bardouble",   "42.0")
            .expectAbsentLong("DOUBLE:foostring.bardouble")
            .expect("DOUBLE:foostring.bardouble",   42D)

            .checkExpectations();
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/reference/ReferenceTestDouble.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.reference;

import nl.basjes.parse.core.Casts;
import nl.basjes.parse.core.Dissector;
import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.test.DissectorTester;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.EnumSet;
import java.util.List;

import static nl.basjes.parse.core.Casts.STRING_ONLY;

/**
 * These tests validate what happens if two dissectors want the SAME input to work on
 */
public class ReferenceTestDouble {

    @Test
    public void verifyRemap() {
        DissectorTester.create()
            .withDissector(new RemapInputDissector())
            .withInput("Doesn't matter")
            .expect("INPUT:",  "42")
            .checkExpectations();
    }


    @Test
    public void verifyFooInput() {
        DissectorTester.create()
            .withDissector(new FooInputDissector())
            .withInput("Doesn't matter")
            .expect("ANY:fooany",                   "42")
            .expect("ANY:fooany",                   42L)
            .expect("ANY:fooany",                   42D)
            .expect("STRING:foostring",             "42")
            .expectAbsentLong("STRING:foostring")
            .expectAbsentDouble("STRING:foostring")
            .expect("INT:fooint",                   "42")
            .expect("INT:fooint",                   42L)
            .expectAbsentDouble("INT:fooint")
            .expect("LONG:foolong",                 "42")
            .expect("LONG:foolong",                 42L)
            .expectAbsentDouble("LONG:foolong")
            .expect("FLOAT:foofloat",               "42.0")
            .expectAbsentLong("FLOAT:foofloat")
            .expect("FLOAT:foofloat",               42D)
            .expect("DOUBLE:foodouble",             "42.0")
            .expectAbsentLong("DOUBLE:foodouble")
            .expect("DOUBLE:foodouble",             42D)
//            .verbose()
            .checkExpectations();
    }

    @Test
    public void verifyBarInput() {
        DissectorTester.create()
            .withDissector(new BarInputDissector())
            .withInput("Doesn't matter")
            .expect("ANY:barany",        "42")
            .expect("ANY:barany",        42L)
            .expect("ANY:barany",        42D)
            .expect("STRING:barstring",  "42")
            .expectAbsentLong("STRING:barstring")
            .expectAbsentDouble("STRING:barstring")
            .expect("INT:barint",        "42")
            .expect("INT:barint",        42L)
            .expectAbsentDouble("INT:barint")
            .expect("LONG:barlong",      "42")
            .expect("LONG:barlong",      42L)
            .expectAbsentDouble("LONG:barlong")
            .expect("FLOAT:barfloat",    "42.0")
            .expectAbsentLong("FLOAT:barfloat")
            .expect("FLOAT:barfloat",    42D)
            .expect("DOUBLE:bardouble",  "42.0")
            .expectAbsentLong("DOUBLE:bardouble")
            .expect("DOUBLE:bardouble",  42D)
//            .verbose()
            .checkExpectations();
    }

    @Test
    public void runDoubleDissectors(){
        DissectorTester.create()
//            .verbose()

            .withDissector(new InputCreatingDissector())
            .withDissector(new RemapInputDissector())
            .withDissector(new FooInputDissector())
            .withDissector(new BarInputDissector())
            .withInput("Doesn't matter")

            .expect("ANY:something.fooany",           "42")
            .expect("ANY:something.fooany",           42L)
            .expect("ANY:something.fooany",           42D)
            .expect("STRING:something.foostring",     "42")
            .expectAbsentLong("STRING:something.foostring")
            .expectAbsentDouble("STRING:something.foostring")
            .expect("INT:something.fooint",           "42")
            .expect("INT:something.fooint",           42L)
            .expectAbsentDouble("INT:something.fooint")
            .expect("LONG:something.foolong",         "42")
            .expect("LONG:something.foolong",         42L)
            .expectAbsentDouble("LONG:something.foolong")
            .expect("FLOAT:something.foofloat",       "42.0")
            .expectAbsentLong("FLOAT:something.foofloat")
            .expect("FLOAT:something.foofloat",       42D)
            .expect("DOUBLE:something.foodouble",     "42.0")
            .expectAbsentLong("DOUBLE:something.foodouble")
            .expect("DOUBLE:something.foodouble",     42D)

            .expect("ANY:something.barany",           "42")
            .expect("ANY:something.barany",           42L)
            .expect("ANY:something.barany",           42D)
            .expect("STRING:something.barstring",     "42")
            .expectAbsentLong("STRING:something.barstring")
            .expectAbsentDouble("STRING:something.barstring")
            .expect("INT:something.barint",           "42")
            .expect("INT:something.barint",           42L)
            .expectAbsentDouble("INT:something.barint")
            .expect("LONG:something.barlong",         "42")
            .expect("LONG:something.barlong",         42L)
            .expectAbsentDouble("LONG:something.barlong")
            .expect("FLOAT:something.barfloat",       "42.0")
            .expectAbsentLong("FLOAT:something.barfloat")
            .expect("FLOAT:something.barfloat",       42D)
            .expect("DOUBLE:something.bardouble",     "42.0")
            .expectAbsentLong("DOUBLE:something.bardouble")
            .expect("DOUBLE:something.bardouble",     42D)

//            .printPossible()
//            .printDissectors()
            .checkExpectations();
    }


    public static class InputCreatingDissector extends Dissector {
        @Override
        public void dissect(Parsable parsable, String inputname) throws DissectionFailure {
            parsable.addDissection(inputname, "BASEINPUT", "something", "42");
        }

        @Override
        public String getInputType() {
            return "SOME_LINE";
        }

        @Override
        public List getPossibleOutput() {
            return Collections.singletonList("BASEINPUT:something");
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }
    }


    public static class RemapInputDissector extends Dissector {
        @Override
        public void dissect(Parsable parsable, String inputname) throws DissectionFailure {
            parsable.addDissection(inputname, "INPUT", "", "42");
        }

        @Override
        public String getInputType() {
            return "BASEINPUT";
        }

        @Override
        public List getPossibleOutput() {
            return Collections.singletonList("INPUT:");
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }
    }


    public static class FooInputDissector extends FooDissector {
        @Override
        public String getInputType() {
            return "INPUT";
        }
    }

    public static class BarInputDissector extends BarDissector {
        @Override
        public String getInputType() {
            return "INPUT";
        }
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/DissectorTester.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import nl.basjes.parse.core.Casts;
import nl.basjes.parse.core.Dissector;
import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.ParsedField;
import nl.basjes.parse.core.Parser;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import org.apache.commons.lang3.SerializationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;

public final class DissectorTester implements Serializable {

    private static final Logger LOG = LoggerFactory.getLogger(DissectorTester.class);

    private boolean verbose = false;
    private final List inputValues = new ArrayList<>();
    private final Map expectedStrings = new TreeMap<>();
    private final Map expectedLongs = new TreeMap<>();
    private final Map expectedDoubles = new TreeMap<>();
    private final List expectedValuePresent = new ArrayList<>();
    private final List expectedAbsentStrings = new ArrayList<>();
    private final List expectedAbsentLongs = new ArrayList<>();
    private final List expectedAbsentDoubles = new ArrayList<>();
    private final List expectedPossible = new ArrayList<>();
    private Parser parser = new Parser<>(TestRecord.class);
    private String pathPrefix = "";

    private DissectorTester() {
    }

    public static DissectorTester create() {
        return new DissectorTester();
    }

    public DissectorTester withParser(Parser newParser) {
        this.parser = newParser;
        return this;
    }

    /**
     * Wildcard dissectors at the root doesn't work (yet)
     * So to test these we can create a dummy root dissector that simply inserts a "first level dissector that does nothing"
     * @param fieldName The fieldName of the first level path
     * @param dissector The first REAL dissector for this test
     * @return This DissectorTester
     */
    public DissectorTester withDissector(String fieldName, Dissector dissector) {
        return withDissector(new DummyDissector(dissector.getInputType(), fieldName))
                .withDissector(dissector);
    }

    public DissectorTester withDissector(Dissector dissector) {
        parser.addDissector(dissector);
        if (parser.getAllDissectors().size() == 1) {
            parser.setRootType(dissector.getInputType());
        }
        return this;
    }

    public DissectorTester withInput(String inputValue) {
        this.inputValues.add(inputValue);
        return this;
    }

    private void addStringSetter(String fieldname) {
        try {
            parser.addParseTarget(TestRecord.class.getMethod("setStringValue", String.class, String.class), fieldname);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            fail(e.getMessage());
        }
    }

    private void addLongSetter(String fieldname) {
        try {
            parser.addParseTarget(TestRecord.class.getMethod("setLongValue", String.class, Long.class), fieldname);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            fail(e.getMessage());
        }
    }

    private void addDoubleSetter(String fieldname) {
        try {
            parser.addParseTarget(TestRecord.class.getMethod("setDoubleValue", String.class, Double.class), fieldname);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
            fail(e.getMessage());
        }
    }

    public DissectorTester expect(String fieldname, String expected) {
        fieldname = addPrefix(fieldname);
        expectedStrings.put(fieldname, expected);
        addStringSetter(fieldname);
        return this;
    }

    public DissectorTester expect(String fieldname, Long expected) {
        fieldname = addPrefix(fieldname);
        expectedLongs.put(fieldname, expected);
        addLongSetter(fieldname);
        return this;
    }

    public DissectorTester expect(String fieldname, Integer expected) {
        return expect(fieldname, Long.valueOf(expected));
    }

    public DissectorTester expect(String fieldname, Double expected) {
        fieldname = addPrefix(fieldname);
        expectedDoubles.put(fieldname, expected);
        addDoubleSetter(fieldname);
        return this;
    }

    public DissectorTester expect(String fieldname, Float expected) {
        return expect(fieldname, Double.valueOf(expected));
    }

    public DissectorTester expectNull(String fieldname) {
        fieldname = addPrefix(fieldname);
        expectedStrings.put(fieldname, null);
        addStringSetter(fieldname);
        return this;
    }

    public DissectorTester expectValuePresent(String fieldname) {
        fieldname = addPrefix(fieldname);
        expectedValuePresent.add(fieldname);
        try {
            parser.addParseTarget(TestRecord.class.getMethod("setStringValue", String.class, String.class), fieldname);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return this;
    }

    public DissectorTester expectAbsentString(String fieldname) {
        fieldname = addPrefix(fieldname);
        expectedAbsentStrings.add(fieldname);
        addStringSetter(fieldname);
        return this;
    }

    public DissectorTester expectAbsentLong(String fieldname) {
        fieldname = addPrefix(fieldname);
        expectedAbsentLongs.add(fieldname);
        addLongSetter(fieldname);
        return this;
    }

    public DissectorTester expectAbsentDouble(String fieldname) {
        fieldname = addPrefix(fieldname);
        expectedAbsentDoubles.add(fieldname);
        addDoubleSetter(fieldname);
        return this;
    }

    public DissectorTester expectPossible(String fieldname) {
        fieldname = addPrefix(fieldname);
        expectedPossible.add(fieldname);
        return this;
    }

    public DissectorTester verbose() {
        this.verbose = true;
        return this;
    }

    private static final Pattern PREFIX_INSERTER = Pattern.compile("([^:]+:)([^:]+)");

    public DissectorTester withPathPrefix(String prefix) {
        if (prefix == null || prefix.isEmpty()) {
            pathPrefix = "";
        } else {
            pathPrefix = "$1" + prefix + "$2";
        }
        return this;
    }

    String addPrefix(String field) {
        if (pathPrefix.isEmpty()) {
            return field;
        }
        return PREFIX_INSERTER.matcher(field).replaceAll(pathPrefix);
    }

    private static class ExpectationResult {
        final String expectation;
        final String field;
        final String value;
        final String failReason;

        ExpectationResult(String expectation, String field, Object value, String failReason) {
            this.expectation = expectation;
            this.field = field;
            if (value == null) {
                this.value = null;
            } else {
                this.value = value.toString();
            }
            this.failReason = failReason;
        }
    }

    private void expectEquals(List expectationResults, String fieldName, String msg, Object left, Object right) {
        boolean expression = false;
        String expected = "<<>>";
        if (left == null) {
            if (right == null) {
                expression = true;
            }
        } else {
            expected = left.toString();
            expression = left.equals(right);
        }
        if (expression) {
            expectationResults.add(new ExpectationResult(msg, fieldName, expected, null));
        } else {
            if (right == null) {
                expectationResults.add(new ExpectationResult(msg, fieldName, expected, "Wrong value: <<>>"));
            } else {
                expectationResults.add(new ExpectationResult(msg, fieldName, expected, "Wrong value: "+right));
            }
        }
    }

    public DissectorTester checkExpectations() {
        DissectorTester tester = SerializationUtils.clone(this);
        try {
            return tester.checkExpectationsDirect();
        } catch (AssertionError ae) {
            throw new AssertionError(ae.getMessage());
        }
    }

    private DissectorTester checkExpectationsDirect() {
        if (expectedStrings.isEmpty() &&
            expectedLongs.isEmpty() &&
            expectedDoubles.isEmpty() &&

            expectedValuePresent.isEmpty() &&

            expectedAbsentStrings.isEmpty() &&
            expectedAbsentLongs.isEmpty() &&
            expectedAbsentDoubles.isEmpty() &&

            expectedPossible.isEmpty()) {
            fail("No expected values were specified");
        }
        List results = new ArrayList<>(32);

        results.addAll(checkDissectors());
        results.addAll(checkExpectedValues());
        results.addAll(checkExpectedAbsent());
        results.addAll(checkExpectedPossible());

        summarizeResults(results);
        return this;
    }

    private void summarizeResults(List results) {
        boolean success = true;
        final String headerField            = "Field";
        final String headerCheck            = "Check";
        final String headerExpectedValue    = "Expected Value";
        final String headerFailReason       = "Fail reason";
        int maxExpectation                  = headerField        .length();
        int maxFieldName                    = headerCheck        .length();
        int maxExpectedValue                = headerExpectedValue.length();
        int maxFailReason                   = headerFailReason   .length();

        for (ExpectationResult expectationResult: results) {
            maxExpectation = Math.max(maxExpectation, expectationResult.expectation.length());
            maxFieldName = Math.max(maxFieldName, expectationResult.field.length());
            if (expectationResult.value != null) {
                maxExpectedValue = Math.max(maxExpectedValue, expectationResult.value.length());
            }
            if (expectationResult.failReason != null) {
                success = false;
                maxFailReason = Math.max(maxFailReason, expectationResult.failReason.length());
            }
        }
        if (!success) {
            StringBuilder sb = new StringBuilder(1024);
            sb.append("\n[     ] /").append(padding("", maxExpectation+maxFieldName+maxExpectedValue+maxFailReason+11, '=')).append("\\\n");
            sb
                .append("[     ] | ")
                .append(headerField).append(padding(headerField, maxFieldName))
                .append(" | ")
                .append(headerCheck).append(padding(headerCheck, maxExpectation))
                .append(" | ")
                .append(headerExpectedValue).append(padding(headerExpectedValue, maxExpectedValue))
                .append(" | ")
                .append(headerFailReason).append(padding(headerFailReason, maxFailReason))
                .append(" |")
                .append("\n[     ] +")
                    .append(padding("", maxFieldName+2, '-')).append('+')
                    .append(padding("", maxExpectation+2, '-')).append('+')
                    .append(padding("", maxExpectedValue+2, '-')).append('+')
                    .append(padding("", maxFailReason+2, '-')).append('+')
                .append("\n");

            for (ExpectationResult expectationResult: results) {
                if (expectationResult.failReason == null) {
                    sb.append("[     ] ");
                } else {
                    sb.append("[ERROR] ");
                }
                sb
                    .append("| ")
                    .append(expectationResult.field).append(padding(expectationResult.field, maxFieldName))
                    .append(" | ")
                    .append(expectationResult.expectation).append(padding(expectationResult.expectation, maxExpectation))
                    .append(" | ");
                String value = expectationResult.value;
                if (expectationResult.value == null) {
                    value = " ";
                }
                sb
                    .append(padding(value, maxExpectedValue)).append(value).append(" | ");
                if (expectationResult.failReason == null) {
                    sb.append(padding("", maxFailReason));
                } else {
                    sb.append(expectationResult.failReason).append(padding(expectationResult.failReason, maxFailReason));
                }
                sb.append(" |\n");
            }
            sb.append("[     ] \\").append(padding("", maxExpectation+maxFieldName+maxExpectedValue+maxFailReason+11, '=')).append("/\n");
            fail(sb.toString());
        }
    }

    private List checkExpectedValues() {
        if (expectedStrings.size() +
            expectedLongs.size() +
            expectedDoubles.size() +
            expectedValuePresent.size() == 0) {
            return Collections.emptyList(); // Nothing to do here
        }

        if (inputValues.isEmpty()) {
            fail("No inputvalues were specified");
        }

        List expectationResults = new ArrayList<>(32);

        for (String inputValue : inputValues) {
            if (verbose) {
                LOG.info("Checking for input: {}", inputValue);
            }

            TestRecord result = parse(inputValue);

            if (verbose) {
                LOG.info("Parse completed successfully");
            }

            int longestFieldName = 0;
            Set allFieldNames = new HashSet<>();
            allFieldNames.addAll(expectedStrings.keySet());
            allFieldNames.addAll(expectedLongs.keySet());
            allFieldNames.addAll(expectedDoubles.keySet());
            allFieldNames.addAll(expectedValuePresent);
            for (String key : allFieldNames) {
                longestFieldName = Math.max(longestFieldName, key.length());
            }

            for (Map.Entry expectation : expectedStrings.entrySet()) {
                String fieldName = expectation.getKey();
                if (!result.hasStringValue(fieldName)) {
                    expectationResults.add(new ExpectationResult("String value", fieldName, expectation.getValue(), "Missing"));
                } else {
                    expectEquals(expectationResults, fieldName, "String value",
                        expectation.getValue(), result.getStringValue(fieldName));
                }
                if (verbose) {
                    LOG.info("Passed: String value for '{}'{} was correctly : {}",
                        fieldName, padding(fieldName, longestFieldName), result.getStringValue(fieldName));
                }
            }

            for (Map.Entry expectation : expectedLongs.entrySet()) {
                String fieldName = expectation.getKey();
                if (!result.hasLongValue(fieldName)) {
                    expectationResults.add(new ExpectationResult("Long value", fieldName, expectation.getValue(), "Missing"));
                } else {
                    expectEquals(expectationResults, fieldName, "Long value",
                        expectation.getValue(), result.getLongValue(fieldName));
                }
                if (verbose) {
                    LOG.info("Passed: Long   value for '{}'{} was correctly : {}",
                        fieldName, padding(fieldName, longestFieldName), result.getLongValue(fieldName));
                }
            }

            for (Map.Entry expectation : expectedDoubles.entrySet()) {
                String fieldName = expectation.getKey();
                if (!result.hasDoubleValue(fieldName)) {
                    expectationResults.add(new ExpectationResult("Double value", fieldName, expectation.getValue(), "Missing"));
                } else {
                    expectEquals(expectationResults, fieldName, "Double value",
                        expectation.getValue(), result.getDoubleValue(fieldName));
                }
                if (verbose) {
                    LOG.info("Passed: Double value for '{}'{} was correctly : {}",
                        fieldName, padding(fieldName, longestFieldName), result.getDoubleValue(fieldName));
                }
            }

            for (String fieldName: expectedValuePresent) {
                expectationResults.add(new ExpectationResult("String present", fieldName, null, result.hasStringValue(fieldName) ? null : "Missing"));

                if (verbose) {
                    LOG.info("Passed: A value for '{}'{} was present.", fieldName, padding(fieldName, longestFieldName));
                }
            }

        }
        return expectationResults;
    }

    private List checkExpectedAbsent() {
        if (expectedAbsentStrings.size() +
            expectedAbsentLongs.size() +
            expectedAbsentDoubles.size() == 0) {
            return Collections.emptyList(); // Nothing to do here
        }

        if (inputValues.isEmpty()) {
            fail("No inputvalues were specified");
        }

        List expectationResults = new ArrayList<>(32);

        for (String inputValue : inputValues) {
            if (verbose) {
                LOG.info("Checking for input: {}", inputValue);
            }

            TestRecord result = parse(inputValue);

            if (verbose) {
                LOG.info("Parse completed successfully");
            }

            int longestFieldName = 0;
            Set allFieldNames = new HashSet<>();
            allFieldNames.addAll(expectedAbsentStrings);
            allFieldNames.addAll(expectedAbsentLongs);
            allFieldNames.addAll(expectedAbsentDoubles);
            allFieldNames.addAll(expectedValuePresent);
            for (String key : allFieldNames) {
                longestFieldName = Math.max(longestFieldName, key.length());
            }

            for (String fieldName: expectedAbsentStrings) {
                expectationResults.add(new ExpectationResult("String absent", fieldName,
                    result.getStringValue(fieldName), result.hasStringValue(fieldName) ? "Present" : null));
                if (verbose) {
                    LOG.info("Passed: String value for '{}'{} was correctly absent", fieldName, padding(fieldName, longestFieldName));
                }
            }

            for (String fieldName: expectedAbsentLongs) {
                expectationResults.add(new ExpectationResult("Long absent", fieldName,
                    result.getLongValue(fieldName), result.hasLongValue(fieldName) ? "Present" : null));
                if (verbose) {
                    LOG.info("Passed: Long value for '{}'{} was correctly absent", fieldName, padding(fieldName, longestFieldName));
                }
            }

            for (String fieldName: expectedAbsentDoubles) {
                expectationResults.add(new ExpectationResult("Double absent", fieldName,
                    result.getDoubleValue(fieldName), result.hasDoubleValue(fieldName) ? "Present" : null));
                if (verbose) {
                    LOG.info("Passed: Double value for '{}'{} was correctly absent", fieldName, padding(fieldName, longestFieldName));
                }
            }
        }
        return expectationResults;
    }

    private TestRecord parse(String inputValue) {
        TestRecord testRecord = new TestRecord();
        if (verbose) {
            testRecord.setVerbose();
        }
        try {
            return parser.parse(testRecord, inputValue);
        } catch (DissectionFailure | InvalidDissectorException | MissingDissectorsException e) {
            fail(e.toString());
        }
        return testRecord; // This will never happen
    }

    private List checkExpectedPossible() {
        if (expectedPossible.isEmpty()) {
            return Collections.emptyList();
        }
        List expectationResults = new ArrayList<>(32);

        int longestFieldName = 0;
        for (String fieldName : expectedPossible) {
            longestFieldName = Math.max(longestFieldName, fieldName.length());
        }

        List allpossible = parser.getPossiblePaths();
        for (String fieldName: expectedPossible) {
            expectationResults.add(new ExpectationResult("Fieldname possible", fieldName,
                null, allpossible.contains(fieldName) ? null : "Not possible"));
            if (verbose) {
                LOG.info("Passed: Fieldname '{}'{} is possible.", fieldName, padding(fieldName, longestFieldName));
            }
        }
        return expectationResults;
    }

    private List checkDissectors() {
        List results = new ArrayList<>();
        Set dissectors = parser.getAllDissectors();
        for (Dissector dissector: dissectors) {
            for (String output: dissector.getPossibleOutput()) {
//                String baseMsg = "Dissector " + dissector.getClass().getSimpleName() + " outputs " + output;
                String[] splitOutput = output.split(":", 2);
                if (!splitOutput[0].toUpperCase(Locale.ENGLISH).equals(splitOutput[0])) {
                    results.add(new ExpectationResult("Dissector input type is UPPERcase",
                        dissector.getClass().getSimpleName() + " --> " + output,
                        splitOutput[0].toUpperCase(Locale.ENGLISH),
                        "\"" + splitOutput[0] + "\" is not fully uppercase."));
                }

                if (!splitOutput[1].toLowerCase(Locale.ENGLISH).equals(splitOutput[1])) {
                    results.add(new ExpectationResult("Dissector output name is lowercase",
                        dissector.getClass().getSimpleName() + " --> " + output,
                        splitOutput[1].toLowerCase(Locale.ENGLISH),
                        "\"" + splitOutput[1] + "\" is not fully uppercase."));
                }
            }
            assertNotNull(
                dissector.prepareForDissect("Checking for non-existing input handling",
                                            "Checking for non-existing output handling"),
                "Dissector::prepareForDissect may NEVER return null!!");
        }
        return results;
    }

    private String centerPadding(String name, char center, int longestLeftSide) {
        return padding(name.substring(0, name.indexOf(center)), longestLeftSide);
    }

    private String padding(String name, int longestFieldName) {
        return padding(name, longestFieldName, ' ');
    }

    private String padding(String name, int longestFieldName, char pad) {
        int length = longestFieldName - name.length();
        if (length <= 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(pad);
        }
        return sb.toString();
    }


    public DissectorTester printDissectors() {
        LOG.info("=====================================================");
        LOG.info("Dissectors:");
        LOG.info("=====================================================");

        Set dissectors = parser.getAllDissectors();
        for (Dissector dissector: dissectors) {
            LOG.info("-----------------------------------------------------");
            LOG.info("{} --> {}", dissector.getInputType(), dissector.getClass().getSimpleName());
            for (String output: dissector.getPossibleOutput()) {
                LOG.info(">> {}", output);
            }
        }
        LOG.info("=====================================================");
        return this;
    }

    public DissectorTester printPossible() {
        LOG.info("=====================================================");
        LOG.info("Possible:");
        LOG.info("----------");
        for (String path: parser.getPossiblePaths()) {
            LOG.info("---> {}", path);
        }
        LOG.info("=====================================================");
        return this;
    }

    public List getPossible() {
        return parser.getPossiblePaths();
    }

    public DissectorTester printAllPossibleValues() {
        if (inputValues.isEmpty()) {
            fail("No inputvalues were specified");
        }

        try {
            List possibleFieldNames = parser
                .getPossiblePaths()
                .stream()
                .sorted(Comparator.comparing(o -> o.substring(o.indexOf(":"))))
                .collect(Collectors.toList());

            for (String path: possibleFieldNames) {
                parser.addParseTarget(TestRecord.class.getMethod("setStringValue", String.class, String.class), path);
            }

            for (String inputValue : inputValues) {
                LOG.info("=====================================================");
                LOG.info("All values (except wildcards) for input:{}", inputValue);
                LOG.info("=====================================================");
                for (String path : possibleFieldNames) {
                    parser.addParseTarget(TestRecord.class.getMethod("setStringValue", String.class, String.class), path);
                }
                TestRecord result = parser.parse(inputValue);

                int longestFieldName = 0;
                int longestTypeIndicator = 0;
                for (String fieldName : possibleFieldNames) {
                    longestFieldName = Math.max(longestFieldName, fieldName.substring(fieldName.indexOf(":")).length());
                    longestTypeIndicator = Math.max(longestTypeIndicator, fieldName.indexOf(":"));
                }
                for (String fieldName : result.getAllNames()) {
                    longestFieldName = Math.max(longestFieldName, fieldName.substring(fieldName.indexOf(":")).length());
                }
                longestFieldName += 4;
                for (String fieldName : possibleFieldNames) {
                    String value = result.getStringValue(fieldName);
                    if (value == null) {
                        String wildcardEnd = ".*";
                        if (fieldName.endsWith(wildcardEnd)) {
                            String fieldNamePrefix = fieldName.substring(0, fieldName.length() - wildcardEnd.length());
                            List allNames = result.getAllNames().stream()
                                .filter(f -> f.startsWith(fieldNamePrefix))
                                .filter(f -> !f.substring(fieldNamePrefix.length()+1).contains("."))
                                .sorted()
                                .collect(Collectors.toList());

                            String leftPadding = centerPadding(fieldName, ':', longestTypeIndicator);
                            String rightPadding = padding(fieldName.substring(fieldName.indexOf(":")), longestFieldName);
                            if (allNames.isEmpty()) {
                                LOG.info("Found values for {}{}{}  = []", leftPadding, fieldName, rightPadding);
                            } else {
                                LOG.info("Found values for {}{}", leftPadding, fieldName);
                                for (String name : allNames) {
                                    leftPadding = centerPadding(name, ':', longestTypeIndicator);
                                    rightPadding = padding(name.substring(name.indexOf(":")), longestFieldName);
                                    LOG.info("             --> {}{}{}  = {}", leftPadding, name, rightPadding, result.getStringValue(name));
                                }
                            }
                            continue;
                        } else {
                            value = "<<>>";
                        }
                    }
                    String leftPadding = centerPadding(fieldName, ':', longestTypeIndicator);
                    String rightPadding = padding(fieldName.substring(fieldName.indexOf(":")), longestFieldName);
                    LOG.info("Found value for  {}{}{}  = {}", leftPadding, fieldName, rightPadding, value);
                }

            }
            LOG.info("=====================================================");
        } catch (NoSuchMethodException | InvalidDissectorException | MissingDissectorsException | DissectionFailure e) {
            e.printStackTrace();
            fail("Shouldn't have any exceptions");
        }
        return this;
    }

    public DissectorTester printSeparator() {
        LOG.info("");
        LOG.info("--------------------------------------------------------------------------------");
        LOG.info("");
        return this;
    }

    public static class DummyDissector extends Dissector {

        private String outputType;
        private String fieldName;

        public DummyDissector() {
        }

        public DummyDissector(String newOutputType, String newFieldName) {
            fieldName = newFieldName;
            outputType = newOutputType;
        }

        @Override
        public void dissect(Parsable parsable, String inputname) throws DissectionFailure {
            final ParsedField field = parsable.getParsableField("DUMMYROOT", inputname);
            parsable.addDissection(inputname, outputType, fieldName, field.getValue());
        }

        @Override
        public String getInputType() {
            return "DUMMYROOT";
        }

        @Override
        public List getPossibleOutput() {
            return Collections.singletonList(outputType + ":" + fieldName);
        }

        @Override
        public EnumSet prepareForDissect(String inputname, String outputname) {
            return STRING_ONLY;
        }

        @Override
        protected void initializeNewInstance(Dissector newInstance) {
            DummyDissector dummyDissector = (DummyDissector)newInstance;
            dummyDissector.fieldName = fieldName;
            dummyDissector.outputType = outputType;
        }
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/EmptyValuesDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.Value;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EmptyValuesDissector extends UltimateDummyDissector {
    private static final Logger LOG = LoggerFactory.getLogger(EmptyValuesDissector.class);

    public EmptyValuesDissector() {
    }

    public EmptyValuesDissector(String inputType) {
        super(inputType);
    }

    @Override
    public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
        LOG.info("Outputting \"EMPTY\" values");
        parsable
            .addDissection(inputname, "ANY",    "any",    "")
            .addDissection(inputname, "STRING", "string", "")
            .addDissection(inputname, "INT",    "int",    "")
            .addDissection(inputname, "LONG",   "long",   "")
            .addDissection(inputname, "FLOAT",  "float",  "")
            .addDissection(inputname, "DOUBLE", "double", "");
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/MyDissectorTester.java
================================================
/*
 * Apache HTTPD logparsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package nl.basjes.parse.core.test;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyDissectorTester {
    @Test
    void testPrefixInserter(){
        DissectorTester tester = DissectorTester.create();

        tester.withPathPrefix("Prefix.");
        assertEquals("Foo:Prefix.Bar", tester.addPrefix("Foo:Bar"));

        tester.withPathPrefix("");
        assertEquals("Foo:Bar", tester.addPrefix("Foo:Bar"));

        tester.withPathPrefix("Prefix.");
        assertEquals("Foo:Prefix.Bar", tester.addPrefix("Foo:Bar"));

        tester.withPathPrefix(null);
        assertEquals("Foo:Bar", tester.addPrefix("Foo:Bar"));

        tester.withPathPrefix("Prefix.");
        assertEquals("Foo:Prefix.Bar", tester.addPrefix("Foo:Bar"));
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/NormalValuesDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.Value;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NormalValuesDissector extends UltimateDummyDissector {
    private static final Logger LOG = LoggerFactory.getLogger(NormalValuesDissector.class);

    public NormalValuesDissector() {
    }

    public NormalValuesDissector(String inputType) {
        super(inputType);
    }

    @Override
    public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
        LOG.info("Outputting \"NORMAL\" values");
        parsable
            .addDissection(inputname, "ANY",    "any",    "42")
            .addDissection(inputname, "STRING", "string", "FortyTwo")
            .addDissection(inputname, "INT",    "int",    42)
            .addDissection(inputname, "LONG",   "long",   42L)
            .addDissection(inputname, "FLOAT",  "float",  42F)
            .addDissection(inputname, "DOUBLE", "double", 42D);
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/NullValuesDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import nl.basjes.parse.core.Parsable;
import nl.basjes.parse.core.Value;
import nl.basjes.parse.core.exceptions.DissectionFailure;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NullValuesDissector extends UltimateDummyDissector {
    private static final Logger LOG = LoggerFactory.getLogger(NullValuesDissector.class);

    public NullValuesDissector() {
    }

    public NullValuesDissector(String inputType) {
        super(inputType);
    }

    @Override
    public void dissect(Parsable parsable, String inputname, Value value) throws DissectionFailure {
        LOG.info("Outputting \"NULL\" values");
        parsable
            .addDissection(inputname, "ANY",    "any",    (String) null)
            .addDissection(inputname, "STRING", "string", (String) null)
            .addDissection(inputname, "INT",    "int",    (Long)   null)
            .addDissection(inputname, "LONG",   "long",   (Long)   null)
            .addDissection(inputname, "FLOAT",  "float",  (Double) null)
            .addDissection(inputname, "DOUBLE", "double", (Double) null);
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/TestRecord.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

public class TestRecord {

    private static final Logger LOG = LoggerFactory.getLogger(DissectorTester.class);

    private final Map>  stringMap   = new HashMap<>(32);
    private final Map>    longMap     = new HashMap<>(32);
    private final Map>  doubleMap   = new HashMap<>(32);

    public void setVerbose() {
        this.verbose = true;
    }

    boolean verbose = false;

    public Set getAllNames() {
        Set allNames = new TreeSet<>();
        allNames.addAll(stringMap.keySet());
        allNames.addAll(longMap.keySet());
        allNames.addAll(doubleMap.keySet());
        return allNames;
    }

    public void setStringValue(final String name, final String value) {
        if (verbose) {
            LOG.info("Received String: {} = {}", name, value);
        }
        stringMap.computeIfAbsent(name, s -> new HashSet<>()).add(value);
    }

    public void setLongValue(final String name, final Long value) {
        if (verbose) {
            LOG.info("Received Long  : {} = {}", name, value);
        }
        longMap.computeIfAbsent(name, s -> new HashSet<>()).add(value);
    }

    public void setDoubleValue(final String name, final Double value) {
        if (verbose) {
            LOG.info("Received Double: {} = {}", name, value);
        }
        doubleMap.computeIfAbsent(name, s -> new HashSet<>()).add(value);
    }

    public String  getStringValue(final String name) {
        Set value = stringMap.get(name);
        if (value == null) {
            return null;
        }
        return value.iterator().next();
    }

    public Long    getLongValue(final String name) {
        Set value = longMap.get(name);
        if (value == null) {
            return null;
        }
        return value.iterator().next();
    }

    public Double  getDoubleValue(final String name) {
        Set value = doubleMap.get(name);
        if (value == null) {
            return null;
        }
        return value.iterator().next();
    }

    public Set  getStringValues(final String name) {
        return stringMap.get(name);
    }

    public Set    getLongValues(final String name) {
        return longMap.get(name);
    }

    public Set  getDoubleValues(final String name) {
        return doubleMap.get(name);
    }

    public boolean hasStringValue(final String name) {
        return stringMap.containsKey(name);
    }

    public boolean hasLongValue(final String name) {
        return longMap.containsKey(name);
    }

    public boolean hasDoubleValue(final String name) {
        return doubleMap.containsKey(name);
    }

    public TestRecord expectString(String field, String... values) {
        if (values == null){
            isPresent(stringMap, field, values);
        } else {
            for (String value : values) {
                isPresent(stringMap, field, value);
            }
        }
        return this;
    }

    public TestRecord expectLong(String field, Long... values) {
        if (values == null){
            isPresent(longMap, field, values);
        } else {
            for (Long value : values) {
                isPresent(longMap, field, value);
            }
        }
        return this;
    }

    public TestRecord expectDouble(String field, Double... values) {
        if (values == null){
            isPresent(doubleMap, field, values);
        } else {
            for (Double value : values) {
                isPresent(doubleMap, field, value);
            }
        }
        return this;
    }

    private void isPresent(Map results, String field, Object value) {
        if (value == null) {
            assertTrue(results.containsKey(field), "The field \""+field+"\" is missing (a null value was expected).");
            Object actualValue = results.get(field);
            assertNotNull(actualValue, "The field \"" + field + "\" should be present but it is not");
            assertTrue(actualValue instanceof Set, "Invalid type used, result must be a Set");
            Set actualValues = (Set)actualValue;
            for (Object actualValuee: actualValues) {
                assertNull(actualValuee, "The field \"" + field + "\" should only have null values but we found: " +
                    "(" + actualValue.getClass().getSimpleName() + ")\"" + actualValue + "\" ");
            }
        } else {
            assertTrue(results.containsKey(field),
                "The field \""+field+"\" is missing (an entry of type "+value.getClass().getSimpleName()+" was expected).");
            Object result = results.get(field);
            assertTrue(result instanceof Set, "Invalid type used, result must be a Set");
            Set resultSet = (Set)result;
            assertTrue(resultSet.contains(value),
                "The field \"" + field + "\" should have the value (" + value + ")\"" + value + "\"is missing");
        }
    }

    public TestRecord noString(String field) {
        isAbsent(stringMap, field);
        return this;
    }

    public TestRecord noLong(String field) {
        isAbsent(longMap, field);
        return this;
    }

    public TestRecord noDouble(String field) {
        isAbsent(doubleMap, field);
        return this;
    }

    private void isAbsent(Map results, String field) {
        Object value = results.get(field);
        if (value != null) {
            fail("The value \""+value+"\" was found for field \""+field+"\"");
        } else {
            assertFalse(results.containsKey(field) || results.get(field) != null,
                "A null value was found for field \"" + field + "\"");
        }
    }

    public void clear() {
        stringMap.clear();
        longMap.clear();
        doubleMap.clear();
    }
}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/TestUltimateDummyDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import org.junit.jupiter.api.Test;

class TestUltimateDummyDissector {

    @Test
    void verifyUltimateDummyDissector() {
        DissectorTester.create()
            .withDissector(new NormalValuesDissector())
            .withInput("Doesn't matter")
            .expect("ANY:any",        "42")
            .expect("ANY:any",        42L)
            .expect("ANY:any",        42D)
            .expect("STRING:string",  "FortyTwo")
            .expectAbsentLong("STRING:string")
            .expectAbsentDouble("STRING:string")
            .expect("INT:int",        "42")
            .expect("INT:int",        42L)
            .expectAbsentDouble("INT:int")
            .expect("LONG:long",      "42")
            .expect("LONG:long",      42L)
            .expectAbsentDouble("LONG:long")
            .expect("FLOAT:float",    "42.0")
            .expectAbsentLong("FLOAT:float")
            .expect("FLOAT:float",    42D)
            .expect("DOUBLE:double",  "42.0")
            .expectAbsentLong("DOUBLE:double")
            .expect("DOUBLE:double",  42D)
//            .verbose()
            .checkExpectations();
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/TestUltimateDummyDissectorFailurelogging.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class TestUltimateDummyDissectorFailurelogging {

    @Test
    void verifyErrorSituation() {
        AssertionError assertionError = assertThrows(AssertionError.class, () ->
            DissectorTester.create()
                .withDissector(new NormalValuesDissector())
                .withInput("Doesn't matter")
                // All good
                .expect("ANY:any", "42")
                .expect("ANY:any", 42L)
                .expect("ANY:any", 42D)
                .expect("STRING:string", "FortyTwo")
                .expectAbsentLong("STRING:string")
                .expectAbsentDouble("STRING:string")
                .expect("INT:int", "42")
                .expect("INT:int", 42L)
                .expectAbsentDouble("INT:int")
                .expect("LONG:long", "42")
                .expect("LONG:long", 42L)
                .expectAbsentDouble("LONG:long")
                .expect("FLOAT:float", "42.0")
                .expectAbsentLong("FLOAT:float")
                .expect("FLOAT:float", 42D)
                .expect("DOUBLE:double", "42.0")
                .expectAbsentLong("DOUBLE:double")
                .expect("DOUBLE:double", 42D)

                // All bad
                .expect("ANY:any", "43")
                .expect("ANY:any", 43L)
                .expect("ANY:any", 43D)
                .expect("STRING:string", "FortyThree")
                .expectAbsentString("STRING:string")
                .expect("INT:int", "43")
                .expect("INT:int", 43L)
                .expectAbsentLong("INT:int")
                .expect("LONG:long", "43")
                .expect("LONG:long", 43L)
                .expectAbsentLong("LONG:long")
                .expect("FLOAT:float", "43.0")
                .expectAbsentDouble("FLOAT:float")
                .expect("FLOAT:float", 43D)
                .expect("DOUBLE:double", "43.0")
                .expectAbsentDouble("DOUBLE:double")
                .expect("DOUBLE:double", 43D)
                .verbose()
                .checkExpectations()
        );

        assertEquals("\n" +
            "[     ] /========================================================================\\\n"+
            "[     ] | Field         | Check         | Expected Value | Fail reason           |\n"+
            "[     ] +---------------+---------------+----------------+-----------------------+\n"+
            "[ERROR] | ANY:any       | String value  |             43 | Wrong value: 42       |\n" +
            "[ERROR] | DOUBLE:double | String value  |           43.0 | Wrong value: 42.0     |\n" +
            "[ERROR] | FLOAT:float   | String value  |           43.0 | Wrong value: 42.0     |\n" +
            "[ERROR] | INT:int       | String value  |             43 | Wrong value: 42       |\n" +
            "[ERROR] | LONG:long     | String value  |             43 | Wrong value: 42       |\n" +
            "[ERROR] | STRING:string | String value  |     FortyThree | Wrong value: FortyTwo |\n" +
            "[ERROR] | ANY:any       | Long value    |             43 | Wrong value: 42       |\n" +
            "[ERROR] | INT:int       | Long value    |             43 | Wrong value: 42       |\n" +
            "[ERROR] | LONG:long     | Long value    |             43 | Wrong value: 42       |\n" +
            "[ERROR] | ANY:any       | Double value  |           43.0 | Wrong value: 42.0     |\n" +
            "[ERROR] | DOUBLE:double | Double value  |           43.0 | Wrong value: 42.0     |\n" +
            "[ERROR] | FLOAT:float   | Double value  |           43.0 | Wrong value: 42.0     |\n" +
            "[ERROR] | STRING:string | String absent |       FortyTwo | Present               |\n" +
            "[     ] | STRING:string | Long absent   |                |                       |\n" +
            "[     ] | FLOAT:float   | Long absent   |                |                       |\n" +
            "[     ] | DOUBLE:double | Long absent   |                |                       |\n" +
            "[ERROR] | INT:int       | Long absent   |             42 | Present               |\n" +
            "[ERROR] | LONG:long     | Long absent   |             42 | Present               |\n" +
            "[     ] | STRING:string | Double absent |                |                       |\n" +
            "[     ] | INT:int       | Double absent |                |                       |\n" +
            "[     ] | LONG:long     | Double absent |                |                       |\n" +
            "[ERROR] | FLOAT:float   | Double absent |           42.0 | Present               |\n" +
            "[ERROR] | DOUBLE:double | Double absent |           42.0 | Present               |\n" +
            "[     ] \\========================================================================/\n",
            assertionError.getMessage());
    }

}


================================================
FILE: parser-core/src/test/java/nl/basjes/parse/core/test/UltimateDummyDissector.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.core.test;

import nl.basjes.parse.core.Casts;
import nl.basjes.parse.core.SimpleDissector;

import java.util.EnumSet;
import java.util.HashMap;

import static nl.basjes.parse.core.Casts.STRING_ONLY;
import static nl.basjes.parse.core.Casts.STRING_OR_DOUBLE;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG;
import static nl.basjes.parse.core.Casts.STRING_OR_LONG_OR_DOUBLE;

/**
 * A dummy dissector to ensure retrieving all types works in the various wrappers
 */
public abstract class UltimateDummyDissector extends SimpleDissector {

    private static final HashMap> DISSECTOR_CONFIG = new HashMap<>();
    static {
        DISSECTOR_CONFIG.put("ANY:any",         STRING_OR_LONG_OR_DOUBLE);
        DISSECTOR_CONFIG.put("STRING:string",   STRING_ONLY);
        DISSECTOR_CONFIG.put("INT:int",         STRING_OR_LONG);
        DISSECTOR_CONFIG.put("LONG:long",       STRING_OR_LONG);
        DISSECTOR_CONFIG.put("FLOAT:float",     STRING_OR_DOUBLE);
        DISSECTOR_CONFIG.put("DOUBLE:double",   STRING_OR_DOUBLE);
    }

    public UltimateDummyDissector() {
        super("INPUT", DISSECTOR_CONFIG);
    }

    public UltimateDummyDissector(String inputType) {
        super(inputType, DISSECTOR_CONFIG);
    }

    @Override
    public boolean initializeFromSettingsParameter(String settings) {
        setInputType(settings);
        return true;
    }


}


================================================
FILE: parser-core/src/test/resources/log4j.properties
================================================
#
# Apache HTTPD & NGINX Access log parsing made easy
# Copyright (C) 2011-2023 Niels Basjes
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Root logger option
log4j.rootLogger=DEBUG, stdout
#, file
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.threshold=INFO
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n

## file appender
#log4j.appender.file=org.apache.log4j.RollingFileAppender
#log4j.appender.file.File=target/debug.log
#log4j.appender.file.threshold=DEBUG
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd} %d{ABSOLUTE} [%-5p] %-40c{1}:%5L: %m%n
#log4j.appender.file.Append=false


================================================
FILE: pom.xml
================================================



  4.0.0
  nl.basjes.parse
  parser-parent
  6.0.1-SNAPSHOT
  pom
  Parser -
  A library to allow easy parsing of Apache HTTPD access logs with Java.
  https://github.com/nielsbasjes/logparser

  
    UTF-8
    UTF-8
    21
    21

    2025-12-26T11:16:47Z

    
    3.9.11

    validate

    3.6.0
    13.4.2

    1.18.46
    2.0.18

    6.0.3
    3.0

    3.5.0
    4.2.0
    1.12.1
    2.70.0
    2.2.0

    0.18
    0.8.14

    
    
    @{jacoco.surefireArgLine} -Xmx2048m
  

  
    
      
        org.junit
        junit-bom
        ${junit5.version}
        pom
        import
      
    
  

  

    
      org.slf4j
      slf4j-api
      ${slf4j.version}
    

    
      org.apache.commons
      commons-text
      1.15.0
    

    
      org.junit.jupiter
      junit-jupiter-engine
      test
    

    
      org.junit.jupiter
      junit-jupiter-params
      test
    

    
      org.junit.vintage
      junit-vintage-engine
      test
      
        
          org.hamcrest
          hamcrest-core
        
      
    

    
      org.hamcrest
      hamcrest-core
      ${hamcrest-core.version}
      test
    

    
      org.slf4j
      slf4j-reload4j
      ${slf4j.version}
      test
    

  

  
    
      release
      
        

          
            org.apache.maven.plugins
            maven-gpg-plugin
            3.2.8
            
              
                sign-artifacts
                verify
                
                  sign
                
                
                  
                    --pinentry-mode
                    loopback
                  
                
              
            
          

          
            org.apache.maven.plugins
            maven-source-plugin
            3.4.0
            
              
                attach-sources
                
                  jar-no-fork
                
              
            
          

          
            org.apache.maven.plugins
            maven-javadoc-plugin
            3.12.0
            
              
                attach-javadocs
                
                  jar
                
                
                  
                  true
                
              
            
          

          
          
            org.sonatype.central
            central-publishing-maven-plugin
            0.10.0
            true
            
              central
              Logparser ${project.version}
              
              
              validated
              
                
                devtools
                parse-utils
                PojoGenerator
                
                httpdlog-examples
                java-pojo
                apache-hadoop-mapreduce
                apache-flink
                apache-beam
              
            
          

        
      
    

    
      EnableReportPlugins
      
        
          
            org.jacoco
            jacoco-maven-plugin
          
        
      
    

  

  
    clean package
    
      
        org.apache.maven.pluginsmaven-clean-plugin3.5.0
        org.apache.maven.pluginsmaven-compiler-plugin3.15.0
        org.apache.maven.pluginsmaven-deploy-plugin3.1.4
        org.apache.maven.pluginsmaven-enforcer-plugin3.6.2
        org.apache.maven.pluginsmaven-install-plugin3.1.4
        org.apache.maven.pluginsmaven-jar-plugin3.5.0
        org.apache.maven.pluginsmaven-resources-plugin3.5.0
        org.apache.maven.pluginsmaven-shade-plugin3.6.2
        org.apache.maven.pluginsmaven-surefire-plugin3.5.5
        org.apache.maven.pluginsmaven-assembly-plugin3.8.0
        org.apache.maven.pluginsmaven-toolchains-plugin3.2.0

        
          org.apache.maven.plugins
          maven-checkstyle-plugin
          ${checkstyle-plugin.version}
          
            
              nl.basjes.parse.devtools
              devtools
              ${project.version}
            
            
              com.puppycrawl.tools
              checkstyle
              ${checkstyle.version}
            
          
          
            true
            checkstyle/checkstyle.xml
            checkstyle/suppressions.xml
            true
          
          
          
            
              checkstyle-check
              test
              
                check
              
            
          
        

        
        
          org.jacoco
          jacoco-maven-plugin
          ${jacoco-maven-plugin.version}
          
            
            
              pre-unit-test
              
                prepare-agent
              
              
                
                jacoco.surefireArgLine
              
            
            
            
              post-unit-test
              test
              
                report
              
            
          
        

        
          org.apache.avro
          avro-maven-plugin
          ${avro.version}
        

      
    

    

      
        org.apache.maven.plugins
        maven-toolchains-plugin
        3.2.0
        
          
            
              select-jdk-toolchain
            
            
              [21,22)
            
          
        
      

      
        org.apache.maven.plugins
        maven-release-plugin
        3.3.1
        
          
            nl.basjes.maven.release
            conventional-commits-version-policy
            1.0.9
          
        
        
          true

          Release:
          Release: Version @{releaseLabel}
          Release: Start development of next version
          Release: Rollback the release of @{releaseLabel}

          v@{project.version}
          ConventionalCommitsVersionPolicy
          
            ^v([0-9]+\.[0-9]+(?:\.[0-9]+)?)$
          

          clean verify
          release,deployToSonatype
          false
          false
        
      

      
        org.apache.maven.plugins
        maven-enforcer-plugin
        
          
            Check build environment requirements
            
              enforce
            
            
              
                
                  [21,)
                  Need Java 21 or newer to build.
                
                
                  [${maven.minimal.version},)
                  You must use Maven version ${maven.minimal.version} or newer to build this project.
                  
                  
                  
                
              
            
          

          
            dependency-convergence
            ${depencency-convergence.phase}
            
              enforce
            
            
              
                
              
            
          

        
      

      
        
        io.github.git-commit-id
        git-commit-id-maven-plugin
        10.0.0
        
          
            get-the-git-infos
            validate
            
              revision
            
          
        
        
          yyyy-MM-dd '@' HH:mm:ss z
        
      

      
        org.apache.rat
        apache-rat-plugin
        ${rat.version}
        false
        
        
          
            org.apache.maven.doxia
            doxia-core
            2.1.0
            
              
                xerces
                xercesImpl
              
            
          
        
        
          
            test
            
              check
            
          
        
        
          true
          false
          
            
            **/.git/**
            **/.gitignore
            
            **/.github/FUNDING.yml
            
            **/.classpath
            **/.project
            **/.settings/**
            **/.idea/**
            **/*.iml
            **/*.json
            
            **/src/test/resources/*.log
            **/demolog/*.log
            GeoIP2-TestData/**
            
            **/target/**
            **/dependency-reduced-pom.xml
            docker/_m2/**
            
            **/CNAME
            **/_config.yml
          
        
      

      
        org.apache.maven.plugins
        maven-compiler-plugin
        3.15.0
        
          
            
              org.projectlombok
              lombok
              ${lombok.version}
            
          
        

      

      
        org.apache.maven.plugins
        maven-source-plugin
        3.4.0
      

    
  

  
    devtools
    parser-core
    httpdlog
    examples
    utils
  

  
    
      Apache License, Version 2.0
      https://www.apache.org/licenses/LICENSE-2.0.txt
      repo
    
  

  
    
      Niels Basjes
      niels@basjes.nl
      
        Architect
        Developer
      
      Europe/Amsterdam
    
  

  
    https://github.com/nielsbasjes/logparser
    scm:https://github.com/nielsbasjes/logparser.git
    scm:git:file:///${project.basedir}
    HEAD
  




================================================
FILE: renovate.json
================================================
{
  "extends": [
    "config:base",
    ":semanticCommits",
    ":semanticCommitTypeAll(chore)"
  ],
  "packageRules": [
    {
      "description": "Disable special versions",
      "matchPackagePatterns": ["*"],
      "allowedVersions": "!/^(?i).*[-_\\.](Alpha|Beta|RC|M|EA|Snap|snapshot|jboss|atlassian)[-_\\.]?[0-9]?.*$/"
    },
    {
      "description": "Disable major updates for centos",
      "matchPackageNames": ["centos"],
      "matchUpdateTypes": ["major"],
      "enabled": false
    }
  ]
}


================================================
FILE: start-docker.sh
================================================
#!/bin/bash
#
# Apache HTTPD & NGINX Access log parsing made easy
# Copyright (C) 2011-2023 Niels Basjes
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"

echo "PWD: ${SCRIPTDIR}"

cd "${SCRIPTDIR}" || ( echo "This should not be possible" ; exit 1 )

PROJECTNAME=logparser
USER=$(id -un)
CONTAINER_NAME=${PROJECTNAME}-devtools-${USER}-$$
DOCKER_BUILD="docker build"

if [ -n "${INSIDE_DOCKER+x}" ];
then
  echo "Nothing to do: You are already INSIDE the docker environment"
  exit 1;
fi

if [[ "$(docker images -q ${PROJECTNAME}-devtools 2> /dev/null)" == "" ]]; then
#  DOCKER_BUILD="docker build"
cat << "Welcome-message"

 _____      _   _   _                                             _                                      _
/  ___|    | | | | (_)                                           (_)                                    | |
\ `--.  ___| |_| |_ _ _ __   __ _   _   _ _ __     ___ _ ____   ___ _ __ ___  _ __  _ __ ___   ___ _ __ | |_
 `--. \/ _ \ __| __| | '_ \ / _` | | | | | '_ \   / _ \ '_ \ \ / / | '__/ _ \| '_ \| '_ ` _ \ / _ \ '_ \| __|
/\__/ /  __/ |_| |_| | | | | (_| | | |_| | |_) | |  __/ | | \ V /| | | | (_) | | | | | | | | |  __/ | | | |_
\____/ \___|\__|\__|_|_| |_|\__, |  \__,_| .__/   \___|_| |_|\_/ |_|_|  \___/|_| |_|_| |_| |_|\___|_| |_|\__|
                             __/ |       | |
                            |___/        |_|

 For building Logparser project

 This will take a few minutes...
Welcome-message
else
  DOCKER_BUILD="docker build -q"
  echo "Loading LogParser development environment"
fi

${DOCKER_BUILD} -t ${PROJECTNAME}-devtools devtools/docker/

buildStatus=$?

if [ ${buildStatus} -ne 0 ];
then
    echo "Building the docker image failed."
    exit ${buildStatus}
fi

if [ "$(uname -s)" == "Linux" ]; then
  USER_NAME=${SUDO_USER:=${USER}}
  USER_ID=$(id -u "${USER_NAME}")
  GROUP_ID=$(id -g "${USER_NAME}")
else # boot2docker uid and gid
  USER_NAME=${USER}
  USER_ID=1000
  GROUP_ID=50
fi

EXTRA_DOCKER_STEPS=""

if [ -f "${HOME}/.gitconfig" ];
then
  cp "${HOME}/.gitconfig" ___git_config_for_docker
  EXTRA_DOCKER_STEPS="ADD ___git_config_for_docker /home/${USER}/.gitconfig"
fi

DOCKER_GROUP_ID=$(getent group docker | cut -d':' -f3)

cat - > ___UserSpecificDockerfile << UserSpecificDocker
FROM ${PROJECTNAME}-devtools
RUN bash /scripts/configure-for-user.sh "${USER_NAME}" "${USER_ID}" "${GROUP_ID}" "$(grep -F vboxsf /etc/group)"
#RUN groupmod -g ${DOCKER_GROUP_ID} docker
${EXTRA_DOCKER_STEPS}
UserSpecificDocker

${DOCKER_BUILD} -t "${PROJECTNAME}-devtools-${USER_NAME}" -f ___UserSpecificDockerfile .

buildStatus=$?

if [ ${buildStatus} -ne 0 ];
then
    echo "Building the user specific docker image failed."
    exit ${buildStatus}
fi

rm -f ___git_config_for_docker ___UserSpecificDockerfile

echo ""
echo "Docker image build completed."
echo "=============================================================================================="
echo ""

# Do NOT Map the real ~/.m2 directory !!!
[ -d "${PWD}/devtools/docker/_m2"    ] || mkdir "${PWD}/devtools/docker/_m2"
[ -d "${PWD}/devtools/docker/_gnupg" ] || mkdir "${PWD}/devtools/docker/_gnupg"

MOUNTGPGDIR="${PWD}/devtools/docker/_gnupg"

if [[ "${1}" == "RELEASE" ]];
then
  cp "${HOME}"/.m2/*.xml "${PWD}/devtools/docker/_m2"
  MOUNTGPGDIR="${HOME}/.gnupg"

  echo "Setting up for release process"
fi

DOCKER_INTERACTIVE_RUN=${DOCKER_INTERACTIVE_RUN-"-i -t"}

DOCKER_SOCKET_MOUNT=""
if [ -S /var/run/docker.sock ];
then
  DOCKER_SOCKET_MOUNT="-v /var/run/docker.sock:/var/run/docker.sock${V_OPTS:-}"
  echo "Enabling Docker support with the docker build environment."
else
  echo "There is NO Docker support with the docker build environment."
fi

COMMAND=( "$@" )
if [ $# -eq 0 ];
then
  COMMAND=( "bash" "-i" )
  DOCKER_INTERACTIVE="-i -t"
else
  DOCKER_INTERACTIVE="-i"
fi

# man docker-run
# When using SELinux, mounted directories may not be accessible
# to the container. To work around this, with Docker prior to 1.7
# one needs to run the "chcon -Rt svirt_sandbox_file_t" command on
# the directories. With Docker 1.7 and later the z mount option
# does this automatically.
# Since Docker 1.7 was release 5 years ago we only support 1.7 and newer.
V_OPTS=:z

docker run --rm=true ${DOCKER_INTERACTIVE}                      \
       -u "${USER_NAME}"                                        \
       -v "${PWD}:/home/${USER_NAME}/${PROJECTNAME}${V_OPTS:-}" \
       -v "${HOME}/.m2:/home/${USER_NAME}/.m2${V_OPTS:-}"       \
       -v "${MOUNTGPGDIR}:/home/${USER_NAME}/.gnupg${V_OPTS:-}" \
       ${DOCKER_SOCKET_MOUNT}                                   \
       -w "/home/${USER}/${PROJECTNAME}"                        \
       -p 1313:1313                                             \
       --name "${CONTAINER_NAME}"                               \
       "${PROJECTNAME}-devtools-${USER_NAME}"                   \
       "${COMMAND[@]}"

exit 0


================================================
FILE: utils/PojoGenerator/pom.xml
================================================



  4.0.0

  
    nl.basjes.parse.utils
    parse-utils
    6.0.1-SNAPSHOT
  

  PojoGenerator

  Parser - Utils - Pojo Generator

  
    
      args4j
      args4j
      2.37
    
    
      nl.basjes.parse.httpdlog
      httpdlog-parser
      ${project.version}
    
    
      org.slf4j
      slf4j-simple
      ${slf4j.version}
    
  



================================================
FILE: utils/PojoGenerator/src/main/java/nl/basjes/parse/httpdlog/PojoGenerator.java
================================================
/*
 * Apache HTTPD & NGINX Access log parsing made easy
 * Copyright (C) 2011-2023 Niels Basjes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.basjes.parse.httpdlog;

import nl.basjes.parse.core.Casts;
import nl.basjes.parse.core.exceptions.InvalidDissectorException;
import nl.basjes.parse.core.exceptions.MissingDissectorsException;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;

import java.util.List;

public class PojoGenerator {
    @Option(name = "-logformat", usage = "", required = true)
    private static final String LOG_FORMAT = "common";

    static class MyRecord {
        public void setter(String name, String value) {
            System.out.println("SETTER CALLED FOR \"" + name + "\" = \"" + value + "\"");
        }
    }

    public static void main(String[] args) throws NoSuchMethodException, MissingDissectorsException, InvalidDissectorException {
        PojoGenerator generator = new PojoGenerator();
        CmdLineParser parser = new CmdLineParser(generator);
        try {
            parser.parseArgument(args);
            generator.run();
        } catch (CmdLineException e) {
            // handling of wrong arguments
            System.err.println(e.getMessage());
            parser.printUsage(System.err);
        }
    }

    public void run() throws NoSuchMethodException, MissingDissectorsException, InvalidDissectorException {
        HttpdLoglineParser parser = new HttpdLoglineParser<>(MyRecord.class, LOG_FORMAT);

        List allPossiblePaths = parser.getPossiblePaths();
        parser.addParseTarget(MyRecord.class.getMethod("setter", String.class, String.class), allPossiblePaths);

        System.out.println("class MyRecord {\n");

        for (String field : parser.getPossiblePaths()) {
            for (Casts cast : parser.getCasts(field)) {
                System.out.println("    @Field{\"" + field + "\"}\n" +
                        "    public void setter(String name, " + castToJavaType(cast) + " value) {\n" +
                        "        System.out.println(\"SETTER CALLED FOR \\\"\" + name + \"\\\" = \\\"\" + value + \"\\\"\");\n" +
                        "    }\n");
            }
        }
        System.out.println("}\n");
    }

    private String castToJavaType(Casts casts) {
        switch (casts) {
            case STRING:
                return "String";
            case LONG:
                return "Long";
            case DOUBLE:
                return "Double";
            default:
                return null;
        }
    }

}



================================================
FILE: utils/pom.xml
================================================



  4.0.0
  
    parser-parent
    nl.basjes.parse
    6.0.1-SNAPSHOT
  

  nl.basjes.parse.utils
  parse-utils
  pom
  Parser - Utils -

  
    
      
        org.apache.maven.plugins
        maven-deploy-plugin
        
          true
        
      
      
        org.apache.maven.plugins
        maven-checkstyle-plugin
      
      
      
        org.jacoco
        jacoco-maven-plugin
        
          true
        
      

    
  

  
    PojoGenerator